188浏览
查看: 188|回复: 12

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

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

驴友花雕  中级技神
 楼主|

发表于 7 天前

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

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

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

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 7 天前

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

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

  1. /*
  2.   【花雕动手做】为 Arduino 机器人创建迷人的 OLED 眼睛动画!
  3.    实验项目之二:OLED 眼睛:呈现多样情绪,增强交互魅力
  4. */
  5. #include <SPI.h>                // 引入SPI通信库,用于支持SPI协议
  6. #include <Wire.h>               // 引入I2C通信库,用于支持I2C协议
  7. #include <Adafruit_GFX.h>       // 引入Adafruit图形库,提供基本图形绘制功能
  8. #include <Adafruit_SSD1306.h>   // 引入Adafruit SSD1306 OLED屏幕驱动库
  9. #define SCREEN_WIDTH 128        // 定义OLED屏幕的宽度为128像素
  10. #define SCREEN_HEIGHT 64        // 定义OLED屏幕的高度为64像素
  11. #define OLED_RESET -1           // 定义OLED复位引脚为-1(表示共享Arduino复位引脚)
  12. #define SCREEN_ADDRESS 0x3C     // 定义OLED屏幕的I2C地址为0x3C(根据屏幕型号选择)
  13. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);  // 创建SSD1306屏幕对象,使用I2C通信
  14. int demo_mode = 1;              // 定义演示模式标志,1表示循环播放动画
  15. static const int max_animation_index = 8;  // 定义最大动画索引为8
  16. int current_animation_index = 0;  // 定义当前动画索引为0
  17. int ref_eye_height = 40;        // 定义参考眼睛高度为40像素
  18. int ref_eye_width = 40;         // 定义参考眼睛宽度为40像素
  19. int ref_space_between_eye = 10; // 定义两只眼睛之间的间距为10像素
  20. int ref_corner_radius = 10;     // 定义眼睛圆角半径为10像素
  21. int left_eye_height = ref_eye_height;  // 定义左眼当前高度为参考高度
  22. int left_eye_width = ref_eye_width;    // 定义左眼当前宽度为参考宽度
  23. int left_eye_x = 32;                   // 定义左眼X坐标为32
  24. int left_eye_y = 32;                   // 定义左眼Y坐标为32
  25. int right_eye_x = 32 + ref_eye_width + ref_space_between_eye;  // 定义右眼X坐标为左眼X坐标加上眼睛宽度和间距
  26. int right_eye_y = 32;                   // 定义右眼Y坐标为32
  27. int right_eye_height = ref_eye_height;  // 定义右眼当前高度为参考高度
  28. int right_eye_width = ref_eye_width;    // 定义右眼当前宽度为参考宽度
  29. void draw_eyes(bool update = true) {  // 定义绘制眼睛函数,update参数控制是否更新屏幕
  30.     display.clearDisplay();           // 清空屏幕
  31.     int x = int(left_eye_x - left_eye_width / 2);  // 计算左眼的左上角X坐标
  32.     int y = int(left_eye_y - left_eye_height / 2); // 计算左眼的左上角Y坐标
  33.     display.fillRoundRect(x, y, left_eye_width, left_eye_height, ref_corner_radius, SSD1306_WHITE);  // 绘制左眼
  34.     x = int(right_eye_x - right_eye_width / 2);    // 计算右眼的左上角X坐标
  35.     y = int(right_eye_y - right_eye_height / 2);   // 计算右眼的左上角Y坐标
  36.     display.fillRoundRect(x, y, right_eye_width, right_eye_height, ref_corner_radius, SSD1306_WHITE);  // 绘制右眼
  37.     if (update) {  // 如果update为true
  38.         display.display();  // 更新屏幕显示
  39.     }
  40. }
  41. void center_eyes(bool update = true) {  // 定义将眼睛居中函数,update参数控制是否更新屏幕
  42.     left_eye_height = ref_eye_height;  // 重置左眼高度为参考高度
  43.     left_eye_width = ref_eye_width;    // 重置左眼宽度为参考宽度
  44.     right_eye_height = ref_eye_height; // 重置右眼高度为参考高度
  45.     right_eye_width = ref_eye_width;   // 重置右眼宽度为参考宽度
  46.     left_eye_x = SCREEN_WIDTH / 2 - ref_eye_width / 2 - ref_space_between_eye / 2;  // 计算左眼X坐标
  47.     left_eye_y = SCREEN_HEIGHT / 2;    // 计算左眼Y坐标
  48.     right_eye_x = SCREEN_WIDTH / 2 + ref_eye_width / 2 + ref_space_between_eye / 2;  // 计算右眼X坐标
  49.     right_eye_y = SCREEN_HEIGHT / 2;   // 计算右眼Y坐标
  50.     draw_eyes(update);  // 调用绘制眼睛函数
  51. }
  52. void blink(int speed = 12) {  // 定义眨眼函数,speed参数控制眨眼速度
  53.     draw_eyes();  // 绘制眼睛
  54.     for (int i = 0; i < 3; i++) {  // 循环3次,模拟眼睛闭合
  55.         left_eye_height -= speed;  // 左眼高度减小
  56.         right_eye_height -= speed; // 右眼高度减小
  57.         draw_eyes();  // 绘制眼睛
  58.         delay(1);     // 延迟1毫秒
  59.     }
  60.     for (int i = 0; i < 3; i++) {  // 循环3次,模拟眼睛睁开
  61.         left_eye_height += speed;  // 左眼高度增加
  62.         right_eye_height += speed; // 右眼高度增加
  63.         draw_eyes();  // 绘制眼睛
  64.         delay(1);     // 延迟1毫秒
  65.     }
  66. }
  67. void sleep() {  // 定义睡眠函数
  68.     left_eye_height = 2;  // 左眼高度设置为2像素
  69.     right_eye_height = 2; // 右眼高度设置为2像素
  70.     draw_eyes(true);      // 绘制眼睛并更新屏幕
  71. }
  72. void wakeup() {  // 定义唤醒函数
  73.     sleep();  // 调用睡眠函数
  74.     for (int h = 0; h <= ref_eye_height; h += 2) {  // 循环增加眼睛高度
  75.         left_eye_height = h;  // 左眼高度增加
  76.         right_eye_height = h; // 右眼高度增加
  77.         draw_eyes(true);      // 绘制眼睛并更新屏幕
  78.     }
  79. }
  80. void happy_eye() {  // 定义开心眼睛函数
  81.     center_eyes(false);  // 将眼睛居中,但不更新屏幕
  82.     int offset = ref_eye_height / 2;  // 定义偏移量为眼睛高度的一半
  83.     for (int i = 0; i < 10; i++) {  // 循环10次,模拟开心表情
  84.         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);  // 绘制左眼下方的倒三角形
  85.         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);  // 绘制右眼下方的倒三角形
  86.         offset -= 2;  // 偏移量减少
  87.         display.display();  // 更新屏幕
  88.         delay(1);     // 延迟1毫秒
  89.     }
  90.     display.display();  // 更新屏幕
  91.     delay(1000);       // 延迟1秒
  92. }
  93. void saccade(int direction_x, int direction_y) {  // 定义快速眼动函数
  94.     int direction_x_movement_amplitude = 8;  // 定义X方向移动幅度
  95.     int direction_y_movement_amplitude = 6;  // 定义Y方向移动幅度
  96.     int blink_amplitude = 8;                // 定义眨眼幅度
  97.     for (int i = 0; i < 1; i++) {  // 循环1次,模拟眼睛快速移动
  98.         left_eye_x += direction_x_movement_amplitude * direction_x;  // 左眼X坐标移动
  99.         right_eye_x += direction_x_movement_amplitude * direction_x; // 右眼X坐标移动
  100.         left_eye_y += direction_y_movement_amplitude * direction_y;  // 左眼Y坐标移动
  101.         right_eye_y += direction_y_movement_amplitude * direction_y; // 右眼Y坐标移动
  102.         right_eye_height -= blink_amplitude;  // 右眼高度减小
  103.         left_eye_height -= blink_amplitude;   // 左眼高度减小
  104.         draw_eyes();  // 绘制眼睛
  105.         delay(1);     // 延迟1毫秒
  106.     }
  107.     for (int i = 0; i < 1; i++) {  // 循环1次,恢复眼睛状态
  108.         left_eye_x += direction_x_movement_amplitude * direction_x;  // 左眼X坐标移动
  109.         right_eye_x += direction_x_movement_amplitude * direction_x; // 右眼X坐标移动
  110.         left_eye_y += direction_y_movement_amplitude * direction_y;  // 左眼Y坐标移动
  111.         right_eye_y += direction_y_movement_amplitude * direction_y; // 右眼Y坐标移动
  112.         right_eye_height += blink_amplitude;  // 右眼高度增加
  113.         left_eye_height += blink_amplitude;   // 左眼高度增加
  114.         draw_eyes();  // 绘制眼睛
  115.         delay(1);     // 延迟1毫秒
  116.     }
  117. }
  118. void move_big_eye(int direction) {  // 定义大眼睛移动函数
  119.     int direction_oversize = 1;     // 定义眼睛放大幅度
  120.     int direction_movement_amplitude = 2;  // 定义移动幅度
  121.     int blink_amplitude = 5;       // 定义眨眼幅度
  122.     for (int i = 0; i < 3; i++) {  // 循环3次,模拟眼睛移动和放大
  123.         left_eye_x += direction_movement_amplitude * direction;  // 左眼X坐标移动
  124.         right_eye_x += direction_movement_amplitude * direction; // 右眼X坐标移动
  125.         right_eye_height -= blink_amplitude;  // 右眼高度减小
  126.         left_eye_height -= blink_amplitude;   // 左眼高度减小
  127.         if (direction > 0) {  // 如果方向为正
  128.             right_eye_height += direction_oversize;  // 右眼高度增加
  129.             right_eye_width += direction_oversize;   // 右眼宽度增加
  130.         } else {  // 如果方向为负
  131.             left_eye_height += direction_oversize;   // 左眼高度增加
  132.             left_eye_width += direction_oversize;    // 左眼宽度增加
  133.         }
  134.         draw_eyes();  // 绘制眼睛
  135.         delay(1);     // 延迟1毫秒
  136.     }
  137.     for (int i = 0; i < 3; i++) {  // 循环3次,恢复眼睛状态
  138.         left_eye_x += direction_movement_amplitude * direction;  // 左眼X坐标移动
  139.         right_eye_x += direction_movement_amplitude * direction; // 右眼X坐标移动
  140.         right_eye_height += blink_amplitude;  // 右眼高度增加
  141.         left_eye_height += blink_amplitude;   // 左眼高度增加
  142.         if (direction > 0) {  // 如果方向为正
  143.             right_eye_height += direction_oversize;  // 右眼高度增加
  144.             right_eye_width += direction_oversize;   // 右眼宽度增加
  145.         } else {  // 如果方向为负
  146.             left_eye_height += direction_oversize;   // 左眼高度增加
  147.             left_eye_width += direction_oversize;    // 左眼宽度增加
  148.         }
  149.         draw_eyes();  // 绘制眼睛
  150.         delay(1);     // 延迟1毫秒
  151.     }
  152.     delay(1000);  // 延迟1秒
  153.     center_eyes();  // 将眼睛居中
  154. }
  155. void move_right_big_eye() {
  156.     move_big_eye(1);  // 调用 move_big_eye 函数,传入方向参数 1(向右)
  157. }
  158. void move_left_big_eye() {
  159.     move_big_eye(-1); // 调用 move_big_eye 函数,传入方向参数 -1(向左)
  160. }
  161. void launch_animation_with_index(int animation_index) {  // 定义根据动画索引播放动画的函数
  162.     if (animation_index > max_animation_index) {  // 如果动画索引超过最大值
  163.         animation_index = max_animation_index;    // 将动画索引设置为最大值
  164.     }
  165.     switch (animation_index) {  // 根据动画索引选择动画
  166.         case 0:
  167.             wakeup();  // 播放唤醒动画
  168.             break;
  169.         case 1:
  170.             center_eyes(true);  // 播放眼睛居中动画
  171.             break;
  172.         case 2:
  173.             move_right_big_eye();  // 播放右眼放大动画
  174.             break;
  175.         case 3:
  176.             move_left_big_eye();   // 播放左眼放大动画
  177.             break;
  178.         case 4:
  179.             blink(10);  // 播放眨眼动画(速度10)
  180.             break;
  181.         case 5:
  182.             blink(20);  // 播放眨眼动画(速度20)
  183.             break;
  184.         case 6:
  185.             happy_eye();  // 播放开心眼睛动画
  186.             break;
  187.         case 7:
  188.             sleep();  // 播放睡眠动画
  189.             break;
  190.         case 8:
  191.             center_eyes(true);  // 播放眼睛居中动画
  192.             for (int i = 0; i < 20; i++) {  // 随机快速眼动
  193.                 int dir_x = random(-1, 2);  // 随机X方向
  194.                 int dir_y = random(-1, 2);  // 随机Y方向
  195.                 saccade(dir_x, dir_y);      // 播放快速眼动动画
  196.                 delay(1);                  // 延迟1毫秒
  197.                 saccade(-dir_x, -dir_y);   // 恢复眼睛位置
  198.                 delay(1);                  // 延迟1毫秒
  199.             }
  200.             break;
  201.     }
  202. }
  203. void setup() {  // 定义初始化函数
  204.     display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);  // 初始化屏幕
  205.     Serial.begin(115200);  // 初始化串口通信
  206.     display.clearDisplay();  // 清空屏幕
  207.     display.setTextSize(1);  // 设置文本大小为1
  208.     display.setTextColor(SSD1306_WHITE);  // 设置文本颜色为白色
  209.     display.setCursor(0, 0);  // 设置文本起始位置
  210.     display.println(F("Intellar.ca"));  // 显示文本
  211.     display.display();  // 更新屏幕
  212.     delay(2000);  // 延迟2秒
  213.     sleep();  // 调用睡眠函数
  214.     delay(2000);  // 延迟2秒
  215. }
  216. void loop() {  // 定义主循环函数
  217.     if (demo_mode == 1) {  // 如果演示模式为1
  218.         launch_animation_with_index(current_animation_index++);  // 播放当前动画
  219.         if (current_animation_index > max_animation_index) {  // 如果动画索引超过最大值
  220.             current_animation_index = 0;  // 重置动画索引
  221.         }
  222.     }
  223.     if (Serial.available()) {  // 如果串口有数据
  224.         String data = Serial.readString();  // 读取串口数据
  225.         data.trim();  // 去除数据前后空格
  226.         char cmd = data[0];  // 获取命令字符
  227.         if (cmd == 'A') {  // 如果命令为'A'
  228.             demo_mode = 0;  // 关闭演示模式
  229.             String arg = data.substring(1, data.length());  // 获取参数
  230.             int anim = arg.toInt();  // 将参数转换为整数
  231.             launch_animation_with_index(anim);  // 播放指定动画
  232.             Serial.print(cmd);  // 发送命令字符
  233.             Serial.print(arg);  // 发送参数
  234.         }
  235.     }
  236. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 7 天前

【花雕动手做】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),按顺序循环播放所有动画。
用户可以通过串口命令关闭演示模式并手动选择动画。

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 7 天前

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

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

  1. void draw_eyes(bool update = true) {
  2.     display.clearDisplay(); // 清空屏幕
  3.     int x = int(left_eye_x - left_eye_width / 2);  // 计算左眼的左上角X坐标
  4.     int y = int(left_eye_y - left_eye_height / 2); // 计算左眼的左上角Y坐标
  5.     display.fillRoundRect(x, y, left_eye_width, left_eye_height, ref_corner_radius, SSD1306_WHITE);  // 绘制左眼
  6.     x = int(right_eye_x - right_eye_width / 2);    // 计算右眼的左上角X坐标
  7.     y = int(right_eye_y - right_eye_height / 2);   // 计算右眼的左上角Y坐标
  8.     display.fillRoundRect(x, y, right_eye_width, right_eye_height, ref_corner_radius, SSD1306_WHITE);  // 绘制右眼
  9.     if (update) {  // 如果update为true
  10.         display.display();  // 更新屏幕显示
  11.     }
  12. }
复制代码

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

​2. 眨眼函数

  1. void blink(int speed = 12) {
  2.     draw_eyes();  // 绘制眼睛
  3.     for (int i = 0; i < 3; i++) {  // 循环3次,模拟眼睛闭合
  4.         left_eye_height -= speed;  // 左眼高度减小
  5.         right_eye_height -= speed; // 右眼高度减小
  6.         draw_eyes();  // 绘制眼睛
  7.         delay(1);     // 延迟1毫秒
  8.     }
  9.     for (int i = 0; i < 3; i++) {  // 循环3次,模拟眼睛睁开
  10.         left_eye_height += speed;  // 左眼高度增加
  11.         right_eye_height += speed; // 右眼高度增加
  12.         draw_eyes();  // 绘制眼睛
  13.         delay(1);     // 延迟1毫秒
  14.     }
  15. }
复制代码



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

​3. 快速眼动函数

  1. void saccade(int direction_x, int direction_y) {
  2.     int direction_x_movement_amplitude = 8;  // 定义X方向移动幅度
  3.     int direction_y_movement_amplitude = 6;  // 定义Y方向移动幅度
  4.     int blink_amplitude = 8;                // 定义眨眼幅度
  5.     for (int i = 0; i < 1; i++) {  // 循环1次,模拟眼睛快速移动
  6.         left_eye_x += direction_x_movement_amplitude * direction_x;  // 左眼X坐标移动
  7.         right_eye_x += direction_x_movement_amplitude * direction_x; // 右眼X坐标移动
  8.         left_eye_y += direction_y_movement_amplitude * direction_y;  // 左眼Y坐标移动
  9.         right_eye_y += direction_y_movement_amplitude * direction_y; // 右眼Y坐标移动
  10.         right_eye_height -= blink_amplitude;  // 右眼高度减小
  11.         left_eye_height -= blink_amplitude;   // 左眼高度减小
  12.         draw_eyes();  // 绘制眼睛
  13.         delay(1);     // 延迟1毫秒
  14.     }
  15.     for (int i = 0; i < 1; i++) {  // 循环1次,恢复眼睛状态
  16.         left_eye_x += direction_x_movement_amplitude * direction_x;  // 左眼X坐标移动
  17.         right_eye_x += direction_x_movement_amplitude * direction_x; // 右眼X坐标移动
  18.         left_eye_y += direction_y_movement_amplitude * direction_y;  // 左眼Y坐标移动
  19.         right_eye_y += direction_y_movement_amplitude * direction_y; // 右眼Y坐标移动
  20.         right_eye_height += blink_amplitude;  // 右眼高度增加
  21.         left_eye_height += blink_amplitude;   // 左眼高度增加
  22.         draw_eyes();  // 绘制眼睛
  23.         delay(1);     // 延迟1毫秒
  24.     }
  25. }
复制代码


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


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 7 天前

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

​4. 动画索引切换

  1. void launch_animation_with_index(int animation_index) {
  2.     if (animation_index > max_animation_index) {  // 如果动画索引超过最大值
  3.         animation_index = max_animation_index;    // 将动画索引设置为最大值
  4.     }
  5.     switch (animation_index) {  // 根据动画索引选择动画
  6.         case 0: wakeup();  break;
  7.         case 1: center_eyes(true);  break;
  8.         case 2: move_right_big_eye();  break;
  9.         case 3: move_left_big_eye();   break;
  10.         case 4: blink(10);  break;
  11.         case 5: blink(20);  break;
  12.         case 6: happy_eye();  break;
  13.         case 7: sleep();  break;
  14.         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;
  15.     }
  16. }
复制代码

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

​5. 串口与交互

i
  1. f (Serial.available()) {  // 如果串口有数据
  2.     String data = Serial.readString();  // 读取串口数据
  3.     data.trim();  // 去除数据前后空格
  4.     char cmd = data[0];  // 获取命令字符
  5.     if (cmd == 'A') {  // 如果命令为'A'
  6.         demo_mode = 0;  // 关闭演示模式
  7.         String arg = data.substring(1, data.length());  // 获取参数
  8.         int anim = arg.toInt();  // 将参数转换为整数
  9.         launch_animation_with_index(anim);  // 播放指定动画
  10.         Serial.print(cmd);  // 发送命令字符
  11.         Serial.print(arg);  // 发送参数
  12.     }
  13. }
复制代码

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

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

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

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

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

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

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 7 天前

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

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

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

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 7 天前

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

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

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

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 7 天前

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

实验记录视频(33秒)

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


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





回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 7 天前

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

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

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

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 7 天前

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

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

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

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 7 天前

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

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

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

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 4 天前

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

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

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail