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

方案二:基于SSD1306 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[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眼睛动画项目,适合用于嵌入式设备的趣味展示或交互设计。通过串口命令和动画索引的结合,用户可以灵活控制动画效果。未来可以通过增加更多动画、优化性能和增强交互功能进一步提升项目的趣味性和实用性。
基本的演示模式,实验场景图 动态图

实验记录视频(33秒)
【【花雕动手做】基于 Arduino 的机器人 OLED 眼睛动画:呈现多样情绪,增强交互魅力】
通过串口输入A1-A8,可以指定动画眼睛的模式

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



评论