文章目录
1. 如何使用Arduino构建3D打印的电子动画眼睛
3D打印电子动画眼睛与Arduino
在这个项目中,我们将用Arduino构建一个电子动画的眼睛。首先,它看起来很酷,并且具有简单的机制,我在从事这个项目时学到了很多关于机电一体化的知识。这个电子动画眼睛设计有两个版本,一个是简单版本,一个是高级版本,对于这个项目,我们想构建简单的一个,在这个过程中,我们会让你知道构建体验以及我们遇到的问题。
构建3D打印电子动画眼睛所需的组件
该项目的BOM非常小,因为所有艰苦的工作都是由3D打印机完成的,我们只需要一些螺丝和粗体,其中大部分都可以在当地的业余爱好商店中找到。下面给出了 BOM 的完整列表。
- 6个SG90伺服电机
- 螺钉 M2、M3 和 M4
- Arduino UNO
- 电缆
- 面包板
- 针头
- PLA和3D打印机
处理和组装 - 电子动画眼部
要处理这个项目,我们需要首先打印所有3D模型,您可以在Ikkalebob instructables中找到3D模型。打印完所有3D部件后,您需要打磨眼睛和其他一些所必需的部件,一旦这些部件完成,我们就可以继续进行组装过程。如果您已正确打印每个部件,则您的产品应类似于下图。
组装方式说明一:
-
用10mm/12mm M3螺栓连接两个底座,这个枢轴点用于眼球运动和眼睑的y轴。
-
将伺服器放置到位并用一些4或6mm M2螺钉将其拧入,这用作x轴运动 的执行器
-
使用4/5/6mm M3螺钉将y轴臂连接到底座,并使用4mm或6mm M2螺钉将伺服喇叭安装在从中心算起的第三个孔上。检查上面以确保一切的方向是正确的。
-
通过使用 4/5/6毫米M3螺栓将叉子拧入眼适配器开始构建x轴组件,叉孔应该过大,以便螺钉拧入适配器,一个有趣的角度进入,但你应该能够进去。
-
将三点连接器连接到前叉顶部,M3螺钉将咬入前叉组件中尺寸过小的孔中。还使用5 毫米 M3螺栓将最后一个孔上的伺服臂连接到三点连接器的中心(伺服臂上的孔可能需要钻到2.5 毫米- 2.8毫米以接受螺钉)。我建议您操纵组件以确保它在构建时也能正常移动而不会经常发生摩擦。
-
用 8 mm M3螺钉将眼形中心连杆连接到眼形适配器上,确保中心连杆的平面朝上,倾斜部分朝下。你也可以在这个阶段插入眼睛。
-
用两个 8/12 mm M3螺栓将所有这些拧到底座的中心。
-
以正确的方向加载带有5 个TowerPro SG90舵机的舵机块。
-
比对图形确定哪个眼睑,并用4mm或6mm M2螺钉连接相关连接器,并将伺服臂连接到另一端(使用伺服喇叭上的最后一个孔 - 您可能需要将其钻到1.5毫米- 1.8毫米)。
-
将眼睑连接到底座上,但不要担心连接任何伺服喇叭。
通过参考图形,将代码上传到 arduino 并将所有内容连接起来。如果您需要帮助设置伺服驱动板,请查看Adafruit 指南。现在所有伺服系统都应该通电并处于中立位置,因此利用这个机会将所有伺服臂连接到伺服系统,眼睛在中立位置朝前。您可以将它们插入,然后断开电源以正确拧入它们。y 轴伺服臂在接受螺钉时处于尴尬的位置,但我发现它在没有螺钉的情况下仍然很好。如果您没有,则卸下其中一个眼睑伺服器以将其拧入可能会有所帮助。我建议在此阶段使用操纵杆测试运动以确保没有问题。
对于眼睑,最好将伺服系统设置在闪烁位置,这样您就可以将它们全部排列在中心。通过按住闪烁开关或在其上创建一个短路来执行此操作。一旦所有伺服臂就位,就很容易将它们拧入。
你的模型应该是完整的!如果您想了解如何制作逼真的眼睛,请查看我之前的教程。我还计划很快发布一个教程,向您展示如何制作控制器,如果您有兴趣,请回来查看!
组装方式1使用舵机驱动板的代码:
// Nilheim Mechatronics Simplified Eye Mechanism Code
// Make sure you have the Adafruit servo driver library installed >>>>> https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
// X-axis joystick pin: A1
// Y-axis joystick pin: A0
// Trim potentiometer pin: A2
// Button pin: 2
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define SERVOMIN 140 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX 520 // this is the 'maximum' pulse length count (out of 4096)
// our servo # counter
uint8_t servonum = 0;
int xval;
int yval;
int lexpulse;
int rexpulse;
int leypulse;
int reypulse;
int uplidpulse;
int lolidpulse;
int altuplidpulse;
int altlolidpulse;
int trimval;
const int analogInPin = A0;
int sensorValue = 0;
int outputValue = 0;
int switchval = 0;
void setup() {
Serial.begin(9600);
Serial.println("8 channel Servo test!");
pinMode(analogInPin, INPUT);
pinMode(2, INPUT);
pwm.begin();
pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates
delay(10);
}
// you can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. its not precise!
void setServoPulse(uint8_t n, double pulse) {
double pulselength;
pulselength = 1000000; // 1,000,000 us per second
pulselength /= 60; // 60 Hz
Serial.print(pulselength); Serial.println(" us per period");
pulselength /= 4096; // 12 bits of resolution
Serial.print(pulselength); Serial.println(" us per bit");
pulse *= 1000000; // convert to us
pulse /= pulselength;
Serial.println(pulse);
}
void loop() {
xval = analogRead(A1);
lexpulse = map(xval, 0, 1023, 220, 440);
rexpulse = lexpulse;
switchval = digitalRead(2);
yval = analogRead(A0);
leypulse = map(yval, 0, 1023, 250, 500);
reypulse = map(yval, 0, 1023, 400, 280);
trimval = analogRead(A2);
trimval = map(trimval, 320, 580, -40, 40);
uplidpulse = map(yval, 0, 1023, 400, 280);
uplidpulse -= (trimval - 40);
uplidpulse = constrain(uplidpulse, 280, 400);
altuplidpulse = 680 - uplidpulse;
lolidpulse = map(yval, 0, 1023, 410, 280);
lolidpulse += (trimval / 2);
lolidpulse = constrain(lolidpulse, 280, 400);
altlolidpulse = 680 - lolidpulse;
pwm.setPWM(0, 0, lexpulse);
pwm.setPWM(1, 0, leypulse);
if (switchval == HIGH) {
pwm.setPWM(2, 0, 400);
pwm.setPWM(3, 0, 240);
pwm.setPWM(4, 0, 240);
pwm.setPWM(5, 0, 400);
}
else if (switchval == LOW) {
pwm.setPWM(2, 0, uplidpulse);
pwm.setPWM(3, 0, lolidpulse);
pwm.setPWM(4, 0, altuplidpulse);
pwm.setPWM(5, 0, altlolidpulse);
}
Serial.println(trimval);
delay(5);
}
组装方式的另一种说明:
我们将通过将6个伺服电机中的5个连接到Servo_Block模块,如下图所示。
将Servo_Block连接到Main_Base该Main_Base如下所示。我们还使用了四个12mm M3内六角螺钉来制作设备的支腿。
接下来,我们将双眼的Fork连接Eye_Adaptor。完成后,我们将把Eye_Holder与Eye_adaptor连接,将Three-point_Connector与Fork连接。完成所有这些过程后,它将如下图所示。
完成此操作后,我们将第六个和最后一个伺服器连接到Sub_Base然后用螺钉将Sub_Base连接到Main_Base。在此之后,我们将 PlaceHolder Eye 连接到Eye_Adaptor。我们还用螺钉连接了 X 臂和 Y 臂。
现在,我们将眼睑(Eyelid)连接器连接到Eyelid,并使用M3螺钉从两侧将眼睑固定到位。
如果您正确完成了所有操作,图像将看起来像上面显示的图像,您可以看到我们已经将所有眼睑与眼睑连接器连接在一起,并且我们已经用伺服电机的臂拧紧了它们。完成此操作后,我们可以进入编码过程。
3D打印眼睛电子动画电路
DIY 3D打印电子动画眼睛的示意图如下所示,如您所见,它非常简单易懂。虽然PCA9685 IC(一个16通道12位PWM伺服电机驱动器)在项目设计者和作者提供的原理图中使用,下面是它的电路图:、
但我们不会将其用于该项目,因为Arduino的Servo库可以轻松处理六个Servo。
如前所述,硬件连接非常简单。我们使用Arduino的六个引脚来控制六个伺服电机。如果我们快速浏览一下Arduino的规格,您可以看到Arduino有六个PWM引脚,我们正在使用所有这些引脚来控制所有六个伺服电机。
用于控制电子动画眼睛的Arduino代码
电子动画眼Arduino代码非常简单易懂。为了使此代码正常工作,我们将使用Arduino的Servo.h库。
我们通过包含所需的库并定义控制所有六个伺服电机所需的所有实例来开始我们的代码。
#include <Servo.h>
Servo top_left_eyelid;
Servo bottom_left_eyelid;
Servo top_right_eyelid;
Servo bottom_right_eyelid;
Servo Yarm;
Servo Xarm;
接下来,在setup**()** 设置函数中,我们声明了眼睛的哪个部分连接到Arduino的哪个引脚。这非常有用,因为我们可以将所有连接器并完全按照原样连接它。
top_left_eyelid.attach(10);
bottom_left_eyelid.attach(11);
top_right_eyelid.attach(5);
bottom_right_eyelid.attach(6);
Yarm.attach(9);
Xarm.attach(3);
接下来,我们初始化串行以进行调试,并调用一些函数以保持眼睛睁开和合,并且我们还添加了一些延迟以保持稳定性。
Serial.begin(9600);
open_eye();
eye_ball_centert();
delay(2000);
接下来,是 loop() 函数,但在解释循环函数之前,我们将解释一些更重要的函数,这些函数对于理解循环函数中的内容是必要的。这些功能是最重要的功能,有了这些功能,我们将移动系统的眼球。首先,我们有**open_eye()**函数。如果您查看硬件,则需要顺时针方向移动一个伺服器,逆时针方向移动另一个伺服器,我们将对左右眼睑(eyelid)执行相同的操作。
void open_eye() {
top_left_eyelid.write(55);
bottom_left_eyelid.write(36);
top_right_eyelid.write(2);
bottom_right_eyelid.write(160);
}
接下来是close_eye() 函数,在close_eye函数中,我们将执行与open_eye函数完全相同的事情,但相反。
void close_eye() {
top_left_eyelid.write(2);
bottom_left_eyelid.write(120);
top_right_eyelid.write(46);
bottom_right_eyelid.write(55);
}
接下来,我们有look_up() 和 look_down() 函数。如果您查看硬件,移动设备的Y臂将上下移动眼球。
void look_up() {
Yarm.write(132);
}
void look_down() {
Yarm.write(45);
}
接下来,我们有**eye_ball_left()和eye_ball_right()**函数,它与向上和向下函数相同,唯一的区别在于设备的角度。
void eye_ball_left() {
Xarm.write(50);
}
void eye_ball_right() {
Xarm.write(130);
}
接下来我们有**eye_ball_centert()**函数。在这个函数中,我们将X臂和Y臂设置为90度角,以便我们可以将眼睛移动到头部中心。
void eye_ball_centert() {
Xarm.write(90);
Yarm.write(90);
}
现在我们还有其他一些我写的函数,让我们的生活更轻松。在该列表中,我们首先有**synchronous_close()**函数,调用此函数将关闭并打开一次眼睛。
void synchronous_close() {
close_eye();
delay(420);
open_eye();
delay(222);
}
然后我们有**random_close()**函数,它将随机打开和关闭眼睛。这将产生很酷的效果。
void random_close() {
close_eye();
delay(random(220, 880));
open_eye();
delay(random(220, 880));
}
接下来,我们有**random_movement()函数。在这个函数中,我们在延迟函数中使用了Arduino的random()**函数,使眼睛随机移动。
void random_movement() {
Xarm.write(60);
delay(random(250, 340));
Yarm.write(80);
delay(random(250, 340));
Xarm.write(120);
delay(random(250, 340));
Yarm.write(140);
Xarm.write(60);
delay(random(250, 340));
Yarm.write(80);
delay(random(250, 340));
Xarm.write(120);
delay(random(250, 340));
Yarm.write(140);
eye_ball_centert();
delay(300);
synchronous_close();
random_close();
}
现在我们将解释void loop
函数,它是Arduino的主要函数。在这个函数中,我们将眼睛向左,向右,向中间移动,然后上下移动,然后我们将使眼睛眨眼。我们将这样做几次,并做出随机运动。最后,我们有两个 for 循环。for循环是关于如何实现平滑运动或移动眼球的示例。
void loop() {
eye_ball_left();
delay(680);
eye_ball_right();
delay(680);
eye_ball_centert();
delay(450);
synchronous_close();
eye_ball_centert();
delay(450);
look_up();
delay(400);
look_down();
delay(400);
eye_ball_centert();
delay(300);
random_close();
delay(450);
look_up();
delay(400);
look_down();
delay(400);
random_movement();
delay(400);
eye_ball_centert();
delay(300);
top_left_eyelid.write(2);
bottom_left_eyelid.write(120);
delay(200);
top_left_eyelid.write(55);
bottom_left_eyelid.write(36);
delay(200);
open_eye();
delay(500);
for (int i = 60; i < 120; i++)
{
Xarm.write(i);
Yarm.write(i - 5);
delay(10);
}
eye_ball_centert();
delay(400);
synchronous_close();
for (int i = 120; i > 60; i--) {
Xarm.write(i);
Yarm.write(i - 5);
delay(10);
}
}
这标志着代码部分的结束,我们可以继续到本文的下一部分。
测试和调试3D打印电子动画眼睛
由于该项目的机械部分有点复杂,因此有很多事情在第一次开始时不起作用,因此在本节中,我想讨论这些主题。
我们遇到的第一个问题是eye_place_holders移动不顺畅,eye_place_holders和eye_lids之间有很多摩擦。
这个问题的解决方案是拿掉(lose)固定眼罩和设备底座的螺钉,这些螺钉是上面显示的标记螺钉。
下一个问题是如何将伺服臂连接到eye_lid臂以及X臂和Y臂的臂上。这是一个巨大的问题,因为没有适当的关节,设备将无法顺利工作,因此在下图中,您可以看到所有伺服臂的图片。
除此之外,一切都运行良好,最终结果看起来像下面显示的gif。
无舵机驱动板代码:
#include <Servo.h>
Servo top_left_eyelid;
Servo bottom_left_eyelid;
Servo top_right_eyelid;
Servo bottom_right_eyelid;
Servo Yarm;
Servo Xarm;
void setup() {
top_left_eyelid.attach(10);
bottom_left_eyelid.attach(11);
top_right_eyelid.attach(5);
bottom_right_eyelid.attach(6);
Yarm.attach(9);
Xarm.attach(3);
Serial.begin(9600);
open_eye();
eye_ball_centert();
delay(2000);
}
void loop() {
eye_ball_left();
delay(680);
eye_ball_right();
delay(680);
eye_ball_centert();
delay(450);
synchronous_close();
//synchronous_close();
eye_ball_centert();
delay(450);
look_up();
delay(400);
look_down();
delay(400);
eye_ball_centert();
delay(300);
random_close();
delay(450);
look_up();
delay(400);
look_down();
delay(400);
random_movement();
delay(400);
eye_ball_centert();
delay(300);
top_left_eyelid.write(2);
bottom_left_eyelid.write(120);
delay(200);
top_left_eyelid.write(55);
bottom_left_eyelid.write(36);
delay(200);
open_eye();
delay(500);
for (int i = 60; i < 120; i++)
{
Xarm.write(i);
Yarm.write(i - 5);
delay(10);
}
eye_ball_centert();
delay(400);
synchronous_close();
for (int i = 120; i > 60; i--) {
Xarm.write(i);
Yarm.write(i - 5);
delay(10);
}
}
void random_movement() {
Xarm.write(60);
delay(random(250, 340));
Yarm.write(80);
delay(random(250, 340));
Xarm.write(120);
delay(random(250, 340));
Yarm.write(140);
Xarm.write(60);
delay(random(250, 340));
Yarm.write(80);
delay(random(250, 340));
Xarm.write(120);
delay(random(250, 340));
Yarm.write(140);
eye_ball_centert();
delay(300);
synchronous_close();
random_close();
}
void random_close() {
close_eye();
delay(random(220, 880));
open_eye();
delay(random(220, 880));
}
void synchronous_close() {
close_eye();
delay(420);
open_eye();
delay(222);
}
void eye_ball_left() {
Xarm.write(50);
}
void eye_ball_right() {
Xarm.write(130);
}
void eye_ball_centert() {
Xarm.write(90);
Yarm.write(90);
}
void look_up() {
Yarm.write(132);
}
void look_down() {
Yarm.write(45);
}
void close_eye() {
top_left_eyelid.write(2);
bottom_left_eyelid.write(120);
top_right_eyelid.write(46);
bottom_right_eyelid.write(55);
}
void open_eye() {
top_left_eyelid.write(55);
bottom_left_eyelid.write(36);
top_right_eyelid.write(2);
bottom_right_eyelid.write(160);
}
2. 简化的3D打印电子动画双眼机制
几乎所有组件都可以在没有支撑的情况下轻松打印。以这种方式设计模型确实会牺牲一些功能,但我将来会发布优化的设计。如果您想构建一个功能强大且逼真的眼部机制,不一定使用车床或专业组件等工具,那么这个项目是理想的选择。
这种设计的另一个特点是,它被设计为使用可以替换的咬接眼,并与其他3D打印组件一起使用,以在涂漆的眼睛上投射高度逼真的圆顶。这个过程非常复杂,所以我有另一个关于如何制作眼睛的指导,但如果你更喜欢使用简单的3D打印眼睛,你也可以这样做。
这个项目将需要对你的打印件进行一些后处理,包括一些(手工)钻孔和打磨,但除了基础知识(3D打印机,工艺刀,螺丝刀,艾伦键)之外,不需要特殊的工具。
附件
-
基本下载包.zip
用品
材料和组件:
- 3D打印机材料:PLA。ABS有利于制作逼真的眼睛,但不是必需的。
- 6x SG90 微型舵机: https://amzn.to/2pG3crm
- 各种M2和M3螺钉
- Arduino:该设计是使用Uno进行测试的,但任何具有SDA / SCL引脚,3个模拟输入和数字输入的电路板都可能工作。Arduino Uno: https://amzn.to/2JTs1Hs
- 伺服驱动板:我选择了Adafruit的16通道PWM驱动板: https://amzn.to/2JPOzsx
- 5V电源,4A左右就绰绰有余了。这是我的(http://tiny.cc/is4cdz)
- 一个与我们的电源相匹配的母直流电源插孔,可焊接到伺服驱动器板上
- 连接线: https://amzn.to/2PNPHAQ
- 操纵杆: https://amzn.to/2pKWX5A
- 电位器(10k欧姆一般是一个不错的使用值:https://amzn.to/2NgDF0S)
- 瞬时开关(一些操纵杆内置了这个,但是当它分开时更容易控制:https://amzn.to/36yzCov)
- 10k 电阻器: https://amzn.to/2NBOjyo
工具:
- 销钳手钻可能有助于调整孔尺寸: https://amzn.to/36BZNKM
步骤 1:打印
由于零件很小,打印可能有些挑战,但大多数零件在没有支撑的情况下可以快速轻松地打印。我使用PLA来打印除眼睛以外的所有部位(使用ABS看起来更自然)。还有一些精致的零件需要注意,但是如果您使用质量不错的PLA,并且对打印设置感到满意,那么您应该没问题。最后,我使用了0.2mm的层高,这对于这个模型来说已经足够精确了 - 我怀疑甚至可以用0.3mm。
第 2 步:后期处理
眼睛可以根据需要进行打磨,但是在打印机打印悬垂的模型底部可能需要进行最少的打磨。这只是为了确保眼睛可以在眼睑内平滑旋转。我唯一打磨的其他部分是eye adaptor组件,只是因为它们紧密贴合,并且我打印的底部几层总是有点肿。
这些零件的设计目的是打印出一些孔,尺寸过小,可以直接拧入,而其他孔的尺寸足够大,因此螺钉会紧紧地穿过它们。如果您的打印机正在使孔变小以拧入或平稳旋转,但是您可以使用一点手钻来钻出一些孔以使其更精确,并且自攻丝也是一种选择(尽管PLA通常可以很好地夹住螺钉)。检查图像以获取有关哪些孔应为哪种尺寸的指南。
步骤 3:组装
一旦您的所有零件都打印和处理完毕,您就可以组装模型了!参考视频以了解它们是如何结合在一起的可能会有所帮助。此外,在我下载的一个文件夹中还有所有参考图片,包括您可以查看的完整模型的stl。
-
用10mm / 12mm M3螺栓连接两个底座,该枢轴点用于眼球运动和眼睑的y轴。
-
将伺服器放置到位,并用一些4或6mm M2螺钉将其拧入,这用作x轴运动的执行器
-
使用 4/5/6mm M3 螺钉将 Y 轴臂连接到底座上,并使用 4mm 或 6mm M2 螺钉在距中心的第三个孔上安装伺服喇叭。检查上面以确保所有内容的方向都是正确的。
-
通过将叉子(fork)拧入带有4/ 5 / 6mm M3螺栓的眼部适配器中来开始构建x轴组件,叉孔应过大,以便螺钉固定适配器,一个以有趣的角度进入,但您应该能够将其放入。
-
将three-point connector连接到叉的顶部,M3螺钉将拧入叉组件中尺寸小的孔中。此外,使用5mm M3螺栓将最后一个孔上的伺服臂连接到三点连接器的中心(伺服臂上的孔可能需要钻孔到2.5mm - 2.8mm才能接受螺钉)。我建议操纵组件,以确保在构建组件时,它都能正常移动,而不会定期摩擦。
-
使用 8mm M3 螺钉将眼部中心连杆连接到眼部适配器,确保中心连杆的平坦表面朝上,倾斜部分朝下。您也可以在此阶段插入眼睛。
-
用两个 8/12mm M3 螺栓将所有这些拧到底座的中心。
-
使用 5 个 TowerPro SG90 伺服器加载伺服块,方向正确。
-
使用图形计算出哪个眼睑是哪个,并用4mm或6mm M2螺钉连接相关连接器,并将伺服臂连接到另一端(使用伺服喇叭上的最后一个孔 - 您可能需要将其钻孔到1.5mm - 1.8mm)。
-
将眼睑连接到底座上,但不必担心连接任何伺服喇叭。
附件
- Complete Model.stl下载
步骤4:接线和总装
根据图形,将代码上传到arduino并将所有内容连接起来。如果您需要有关设置伺服驱动器板的帮助,请查看Adafruit指南。现在,所有舵机都应通电并处于空档位置,因此请利用这个机会将所有伺服臂连接到舵机,使眼睛在空档位置朝前。您只需插入它们,然后断开电源即可将其正确拧入。Y轴伺服臂处于一个尴尬的位置,无法接受螺钉,但我发现它无论如何都可以在没有螺钉的情况下保持良好状态。如果你的没有,取下其中一个眼睑伺服器以将其拧入可能会有所帮助。我建议在此阶段使用操纵杆测试运动,以确保没有问题。
对于眼睑,最好将舵机设置为眨眼(blinking)位置,以便将它们全部排在中心。通过按住blink开关或在其上创建短路来执行此操作。一旦所有伺服臂都就位,就很容易将它们拧入。
您的模型应该是完整的!如果你想看看如何使逼真的眼睛,检查我以前的指导。我还计划很快发布一个可说明的,向您展示如何制作控制器,所以如果您有兴趣,请回来查看!