#项目起源#

 

春节是中国最传统,最隆重的节日,春节的习俗有贴春联、放鞭炮、拜年等,当然最温馨的时刻莫过于除夕夜一家人围在一起吃团圆饭、看春晚了。为了庆祝即将到来的虎年春节,旺仔爸爸制作了一个别样的翻页动画显示器,我给他取名叫Page-turning display

 

图 2 翻页动画显示器

 

既然是显示器,那首当其冲的肯定得有屏幕,不过这个屏幕它不是电子的,而是比较古老的翻页式的,类似于快速翻书的效果,其实现在生活荧屏中播放的视频也是一帧一帧的画面切换出现的效果,只不过切换的速度很快,人眼已经无法觉察出来,而我们这次的翻页动画显示器就是要还原这种显示原理

 

下面我们先通过视频来看一下翻页动画显示器是如何工作的

 

#设计制作#

 

我们将翻页动画显示器设计为复古的电视机造型,采用激光切割技术加工椴木板和亚克力板来制作翻页动画显示器的外观结构,下图3为效果图

 

图 3 翻页动画显示器效果仿真图

 

#方案介绍#

 

初步观察上面的仿真图可以知道,翻页动画显示器由三部分组成,分别是:

旋转显示部分、外框架部分和电控部分

 

关于旋转显示部分的驱动电机可以供我们选择的方案有很多,比如步进电机、直流减速电机、舵机等。由于本次旋转部分的负载不是很大,对转速要求不是很高,在旋转的同时还要能够精确控制旋转角度,于是我们选择性价比较高的28BYJ-48微型步进电机,在使用时搭配ULN2003驱动即可工作,大大降低了使用难度,减小了空间体积,步进电机如下图4所示

图 4 28BYJ-48微型步进电机

 

关键的驱动部分解决后,我们选择Arduino Nano作为主控板,同时增加霍尔传感器再配合磁铁实现记录旋转圈数的功能,具体细节如下图5

 

图 5翻页动画显示器内部图

 

方案确定后,我们便可开始设计翻页动画显示器的外观结构

 

#图纸设计#

 

我们使用LaserMaker激光建模软件设计图纸

 

关于建模软件可以登录官方提供的网址下载:https://www.lasermaker.com.cn/

 

图 6 LaserMaker软件下载

 

下载安装完成后打开软件,界面如下图7

 

图 7 LaserMaker软件运行界面

 

在LaserMaker软件中设计复古电视机的造型如图8,作品中用来显示画面的翻页部分我们采用1mm厚度的透明亚克力板,而除此之外的其他结构部分我们选用的加工材料为3mm厚度的椴木板,为了增加作品的互动性,我们设计一个魔法棒作为翻页显示器的启停开关

 

图 8 翻页动画显示器设计图

 

至于翻页显示的动画贴纸需要在网上搜索新年动画素材(或者个人喜欢的动漫素材),修改为与零件相同的尺寸,打印出来,粘贴在亚克力板上

 

图 9 贴纸与亚克力板

 

图 10 贴纸粘贴在亚克力板上

 

#加工零件#

 

图纸设计完成后我们使用激光切割机把它加工出来,切割完成后的零件如下图11所示

 

图 11 激光切割加工完成后的零件实物图

 

#器材清单#

 

除了外观结构外,本次翻页动画显示器还需要使用到如下零件

 

Arduino Nano控制器加扩展板*1

霍尔传感器*2

28BYJ-48步进电机*1

ULN2003步进电机驱动器*

开关*1

DC电源接口*1

3mm椴木板*1(40cm*60cm)

1mm透明亚克力板*2(40cm*60cm)

杜邦线若干

3mm转5mm联轴器*1

20cmD型轴*1

五金件若干

 

图 12 翻页动画显示器器材清单

 

器材准备完成,接下来我们看一下电控部分是如何连接的

 

#电路接线#

 

翻页动画显示器的电路接线如下图13所示

 

步进电机连接控制器的4-7号数字引脚,两个霍尔传感器分别连接2号和3号数字引脚,其中一个霍尔传感器作为启停开关,另一个霍尔传感器用来检测圆盘上的磁铁转了多少圈

图 13翻页动画显示器电路接线示意图

 

一切准备工作就绪,我们即可开始组装作品

 

#组装#

 

翻页动画显示器的组装不算很复杂,但还是需要仔细按步骤安装

 

第一步 安装电子部件

 

首先我们安装翻页显示器的开关,本次作品我们选用一个有些复古味道的钮子开关,将钮子开关安装在正面的木板上,如下图14和图15

 

图 14 安装钮子开关

 

图 15 钮子开关安装完成

 

紧接着,安装控制器、步进电机、驱动器以及电源接口,下图16是所需的零件

 

图 16 电子部件

 

主控及步进电机等部件安装完成如下图17所示

 

图17 主控及步进电机安装完成图

 

接下来,安装用来记录圈数的霍尔传感器,安装完成如下图18所示

 

图 18 霍尔传感器安装完成

第二步 组装框架结构

 

电子部件安装完成,下一步我们需要将框架组装起来,框架如下,由5部分组成,只需要按照插槽拼装即可

 

图 19 框架组装需要的零件

 

框架组装完成如下图20所示

 

图 20 框架组装完成

 

框架完成后,我们需要在框架中安装翻页显示的旋转骨架,所需零件如下图21

 

图 21 安装旋转骨架所需零件示

 

组装时需要将D型轴安装在长方形的盒子中,并在盒子的两侧安装圆盘,安装完成如下图22所示

 

图 22 旋转骨架安装完成

 

旋转骨架组装完成就需要与框架组合在一起了,如下图23所示

 

图 23 旋转骨架与框架组合

 

使用一个直径5mm转3mm的联轴器将步进电机与D型轴连接在一起,而在另外一侧,为了保证轴旋转时的灵活度,我们可以在孔位中安装一个轴承,安装完成如下图24

 

图 24 旋转骨架与框架组合完成

 

下面一步,需要将正面的木板安装在框架上

 

图 25 正面木板与框架组合

 

图 26 正面木板与框架组合完成

 

第三步 安装显示部分和其他

 

现在,“电视机”整体效果已经有了,如果能够再来一个天线将会更有“灵魂”,我们来为“电视机”安装天线和用来启停的魔法棒

 

图 27 安装天线和魔法棒所需零件

 

别忘记在魔法棒的中间装入磁铁,安装完成如下图28

 

图 28天线和魔法棒安装完成

 

最后,我们把最重要的显示画面安装在显示器的骨架中,翻页动画显示器的组装就大功告成了

 

图 29安装显示画面

 

亚克力的画面安装时对准两侧圆盘上的孔位即可,翻页动画显示器组装完成效果如下

 

图 30显示画面安装完成

 

图 31

 

作品组装完成,接下来我们编写程序为作品注入灵魂

 

#程序设计#

 

本次作品程序设计使用Arduino IDE作为编程环境,关于编程环境可以在官网arduino.cc下载

 

图 32

 

当然也可以在mixly.org网站下载最新的Mixly图形化编程软件,软件中集成了 Arduino IDE编程环境,省去了不少配置的麻烦

 

#编程思路#

 

本次我们制作的翻页动画显示器(Page-turning display),使用步进电机让翻页动画显示器转起来,使用两个霍尔传感器用来控制动画播放和记录旋转圈数,那么关于步进电机和霍尔传感器的使用是本次作品程序设计的关键,我们根据编程思路来一步步完成

图 33 程序设计思维导图

 

#霍尔传感器的使用#

 

背景知识

霍尔传感器是基于霍尔效应,可以用来探测磁性材料(磁铁)的传感器。

 

什么是霍尔效应呢?霍尔效应在1879年被物理学家霍尔发现,当一个磁场靠近一个有电流通过的导体时,导体中的电子会由于受到磁场的影响,偏转到一边,这时候导体中会形成一个电势差,这就是霍尔效应,利用这一现象就可以用来探测磁性材料

 

常见的霍尔传感器有开关型霍尔和线性霍尔两种,线性霍尔传感器输出模拟信号,开关型霍尔传感器输出数字信号

 

本次作品我们只需要用霍尔传感器控制翻页动画显示器启停,也就是用开关型的霍尔传感器即可

 

关于霍尔传感器的编程方法很简单,能够检测磁铁有无就可以

 

我们在编程环境中输入如下程序,测试一下霍尔传感器的状态

#define Hall_START 2 //霍尔传感器引脚int START;//开始状态存储变量void setup(){  pinMode(Hall_START, INPUT);//START  Serial.begin(9600);}

void loop(){  START = digitalRead(Hall_START);//存储霍尔传感器的状态  Serial.println(START);  delay(1000);}

 

程序运行结果如下图34

 

当磁铁考近信号为0,磁铁远离信号为1

 

图 34霍尔传感器测试

 

同样的方法可以测试第二个霍尔传感器

 

我们在原有的基础上继续修改程序

 

#define Hall_START 2 //霍尔传感器引脚#define Hall_END 3 //霍尔传感器引脚int START;//开始状态存储变量int END;//结束状态存储变量void setup(){  pinMode(Hall_START, INPUT);//START  pinMode(Hall_END, INPUT);//END  Serial.begin(9600);}void loop(){  START = digitalRead(Hall_START);//存储1号霍尔传感器的状态  END = digitalRead(Hall_END);//存储2号霍尔传感器的状态  Serial.print(F("一号霍尔传感器状态:"));  Serial.println(START);  delay(1000);  Serial.print(F("二号霍尔传感器状态:"));  Serial.println(END);  delay(1000);}

 

程序下载运行后的效果如下图35所示

 

图 35 两个霍尔传感器同时测试

 

这样,两个霍尔传感器都可以控制了

 

下面,我们丰富一下程序,设置当磁铁靠近霍尔传感器超过0.5秒时开始工作,程序如下

 

#define Hall_START 2 //霍尔传感器引脚#define Hall_END 3 //霍尔传感器引脚#define OVER 1    //判断是否进入最终环节int START;//开始状态存储变量int END;//结束状态存储变量bool is_working = false;//工作中bool is_free = true;//空闲int count=0;//计数器int SPEED=0;//speedchar MODEL;          //模式void setup(){  pinMode(Hall_START, INPUT);//START  pinMode(Hall_END, INPUT);//END  Serial.begin(9600);}void loop(){   if(START == 1 && digitalRead(Hall_START) == 0)//两次检测按键的状态  {    delay(500);    if ( digitalRead(Hall_START) == 0 && is_free == true) //且设备处于空闲状态进入工作模式    {      is_free = false;      is_working = true;    }  }  START = digitalRead(Hall_START);//存储1号霍尔传感器的状态  END = digitalRead(Hall_END);//存储2号霍尔传感器的状态   //开始工作  if(is_free == false && is_working == true )  {      Serial.println(F("工作中"));        //计数器计数,忽略第一次检测状态           count++;      Serial.println(count);       if(count >500)  { MODEL = OVER; }  }  //结束工作  if (MODEL == OVER && END == 0)  {    Serial.println(F("结束工作"));    count = 0;//计数器清零    is_working = false;//工作指示变量复位    is_free = true;//空闲指示变量复位    MODEL = 0;//状态复位  }}

 

程序中,我们设置了“START”和“END”两个变量用来存放两个霍尔传感器的数值,用“is_free”和“is_working”两个变量来标记工作状态,用变量“MODEL”来存储工作状态,当检测到磁铁靠近1号霍尔传感器并持续时间超过0.5秒后,即可开始进入工作状态,同时变量“count”开始计数,当变量“count”计数值超过500后结束工作,并将所有变量的状态复位

 

程序下载后的运行结果如下图36,当磁铁靠近霍尔传感器的时间超过0.5秒后开始计数,计数器数值超过500后停止工作

 

图 36 霍尔传感器启停测试

 

如此,我们已经实现了使用磁铁来控制启停的功能,接下来我们只需要在程序中加入步进电机转动的程序即可实现真正的翻页动作

 

下面我们就来学习步进电机的控制方法

 

#步进电机知识#

 

背景知识

这次我们选择的步进电机的型号是28BYJ-48步进电机,它的全名叫永磁型单极性四相步进电机,这么复杂的名字难免让人有些头疼

 

我们先来看一下28BYJ-48步进电机名称的来历

 

28:步进电机的有效最大外径是28毫米

B:表示是步进电机

Y:表示是永磁式

J:表示是减速型(减速比1:64)

48:表示四相八拍

 

换句话说,28BYJ-48的含义为外径28毫米四相八拍式永磁减速型步进电机。是不是有点乱?别慌,我们一点点看

 

通常电机分为定子和转子,转子的每个齿都带有一个永磁体,这既是永磁式的概念

 

定子在外圈,定子上有8个齿,每个齿都缠上了线圈,两两一组,同时导通或关断,如此就形成了4相,这就是4相的概念,至于八拍这里就不展开详细介绍了,你可简单理解为4组线圈的通电顺序

 

接下来,解释名字中的“减速”概念,下图37是28BYJ-48 步进电机的拆解图,

图 37 28BYJ-48步进电机内部图

 

从图中可以看到,位于最中心的那个白色小齿轮是步进电机的转子轴,一个小齿轮带动一个大齿轮为一级减速,图中所示的电机中共有4级减速,那么总的减速比是多少呢?即转子要转多少圈最终输出轴才转一圈呢?

 

回头看一下电机参数表中的减速比参数是1:64,也就是转子转64圈,输出轴转一圈,不管是哪个厂家生产的电机,只要型号是 28BYJ-48,其标称的减速比就都是1:64。

 

关于基本的控制原理就介绍到这里

图 38 图解步进电机减速比

 

实际上单独用控制器控制步进电机还是很困难的,需要一个驱动器来驱动步进电机,ULN2003驱动器与28BYJ-48步进电机是形影不离的好朋友,基本上同时出现

 

熟悉了28BYJ-48步进电机后,我们来编写程序控制步进电机,我们可以选择的步进电机的驱动库有Arduino IDE内置的【Stepper】库和【AccelStepper】第三方库

 

由于Arduino内置的【Stepper】库在控制步进电机的过程中其他程序是无法进行工作的,我们需要用简单易用,功能强大的【AccelStepper】第三方库,让Arduino在控制步进电机的同时完成其它工作。

 

安装AccelStepper库

在Arduino IDE编程环境中,点击工具菜单栏中的【库管理】选项,在输入栏输入【AccelStepper】库并点击安装,如下图39

 

图 39 安装AccelStepper库

 

安装完成后,即可使用该库控制步进电机

 

我们在编程环境中输入如下程序

 

#include "AccelStepper.h"// 电机步进方式定义#define FULLSTEP 4    //全步进参数#define HALFSTEP 8    //半步进参数// 定义步进电机引脚#define motor1Pin1  4     // 28BYJ48连接的ULN2003电机驱动板引脚 in1#define motor1Pin2  5     // 28BYJ48连接的ULN2003电机驱动板引脚 in2#define motor1Pin3  6    // 28BYJ48连接的ULN2003电机驱动板引脚 in3#define motor1Pin4  7    // 28BYJ48连接的ULN2003电机驱动板引脚 in4// 定义步进电机对象// 定义中ULN2003驱动板引脚顺序为 in1-in3-in2-in4// 电机设置为全步进运行AccelStepper stepper(FULLSTEP, motor1Pin1, motor1Pin3, motor1Pin2, motor1Pin4);void setup(){  stepper.setMaxSpeed(500.0);    // 电机最大速度500  stepper.setAcceleration(50.0);  // 电机加速度50.0  Serial.begin(9600);}

void loop(){  if ( stepper.currentPosition() == 0 )  {    // 电机转动一周    stepper.moveTo(2048);                 }   else if ( stepper.currentPosition() == 2048 )  {    // 电机转动一周    stepper.moveTo(0);             }           stepper.run();   // 电机运行}

 

程序中,通过【setMaxSpeed】设置步进电机最大运行速度,通过

 

【setAcceleration】设置步进电机加速度,使用【currentPosition】获取步进电机运行当前位置,【moveTo】指令可以设置步进电机运动的绝对目标位置,即旋转到指定角度,

 

这里步进电机上电时的位置为0

 

程序运行后,我们会看到步进电机会旋转一周后停了下来,为什么stepper.moveTo(2048)是旋转一周呢,这里的2048指的是什么?

 

四相八拍的步进电机步距角是11.25°,转子转一圈需要走360/11.25=32步,减速比是1:64,输出轴转一圈则需要32*64=2048步,

 

那stepper.moveTo(2048)中的2048其实就是让输出轴转一圈所走的步数,当然这是在全步进“#define FULLSTEP 4”的参数下的情况,如果是半步进“#define HALFSTEP 8”,那么转子每走一步的角度为5.625,转子转一圈需要64步,输出轴转一圈就需要4096步了

 

除此之外,【AccelStepper】库还提供了一些其他的常用函数,如下

 

常用函数和操作

       setCurrentPosition -复位步进电机初始位置

 

利用setCurrentPosition函数设置可以修改当前位置的数值,比如,当前步进电机所处在0的位置,

 

输入stepper.setCurrentPosition(512)指令,会将原来0的位置修改为512的位置

 

图 40 图解setCurrentPosition函数

 

move – 设置步进电机运动的相对目标位置

 

stepper.move(1024); // 利用move函数可以使步进电机运行相应步数。

 

比如,当前步进电机处在0的位置,move(512)可以使步进电机转512步指向512的位置,再来一次move(512)指令可以使步进电机指向1024的位置

 

图 41 图解move函数

 

moveTo -设置步进电机运动的绝对目标位置

 

使用moveTo指令可以使步进电机旋转到指定角度,比如moveTo(1024)可以使步进电机指向1024的位置,如果再输入一次moveTo(1024)指令,步进电机由于已经处在1024的位置,则不再动作

 

图 42 图解moveTo函数

 

runToNewPosition – 电机运行到用户指定位置值,目标位置为绝对位置。

stepper.runToNewPosition(2048); //利用runToNewPosition函数让电机运行到用户指定位置值。

 

runToNewPosition指令与前面提到的moveTo(指令类似),只不过runToNewPosition指令在运行的过程中在步进电机没有到达目标位置前,将不会继续执行后续程序内容。

 

图 43 图解runToNewPosition函数

 

setSpeed -设置步进电机运行速度

run -步进电机运行(先加速后减速模式)

runSpeed -步进电机运行(匀速模式)

 

如果需要让步进电机匀速转动,就需要使用setSpeed -设置步进电机运行速度

和runSpeed()函数

 

例如输入如下两条代码,步进电机会以300的速度匀速运行下去

 

stepper.setSpeed(300);  // 初始化电机速度为300stepper.runSpeed();

 

以上为AccelStepper库常用函数介绍(这里引用了太极创客团队提供的资料,感谢太极创客为创客圈做出的贡献)。AccelStepper库还有很多函数没有在这里列举出。我们相信在掌握了以上的函数使用后,对于AccelStepper库的其他函数也会更加容易理解和掌握。如果需要获得更多的AccelStepper库使用资料,请参考http://www.airspayce.com/mikem/arduino/AccelStepper/index.html

 

在本次翻页动画显示器中,我们只需要让步进电机匀速运行,我们将前文中霍尔传感器的程序与步进电机程序结合即可完成翻页动画显示的程序控制

 

完整程序如下

 

#include "AccelStepper.h"// 电机步进方式定义#define FULLSTEP 4    //全步进参数#define HALFSTEP 8    //半步进参数// 定义步进电机引脚#define motor1Pin1  4     // 28BYJ48连接的ULN2003电机驱动板引脚 in1#define motor1Pin2  5     // 28BYJ48连接的ULN2003电机驱动板引脚 in2#define motor1Pin3  6    // 28BYJ48连接的ULN2003电机驱动板引脚 in3#define motor1Pin4  7    // 28BYJ48连接的ULN2003电机驱动板引脚 in4#define Hall_START 2 //霍尔传感器引脚#define Hall_END 3 //霍尔传感器引脚#define OVER 1    //判断是否进入最终环节// 定义步进电机对象// 定义中ULN2003驱动板引脚顺序为 in1-in3-in2-in4// 电机设置为全步进运行AccelStepper stepper(FULLSTEP, motor1Pin1, motor1Pin3, motor1Pin2, motor1Pin4);int START;//开始状态存储变量int END;//结束状态存储变量bool is_working = false;//工作中bool is_free = true;//空闲int count=0;//计数器int SPEED=0;//speedchar MODEL;          //模式void setup(){  pinMode(Hall_START, INPUT);//START  pinMode(Hall_END, INPUT);//END  stepper.setMaxSpeed(500.0);    // 电机最大速度500  stepper.setSpeed(0);      // 初始化电机速度为0  Serial.begin(9600);  //复原到初始位置  while(digitalRead(Hall_END) == 1)  {    stepper.setSpeed(100);    stepper.runSpeed();  }  stepper.setSpeed(0);  stepper.runSpeed(); }void loop(){  if(START == 1 && digitalRead(Hall_START) == 0)//两次检测按键的状态  {    delay(500);    if ( digitalRead(Hall_START) == 0 && is_free == true) //且设备处于空闲状态进入工作模式    {      is_free = false;      is_working = true;    }  }  START = digitalRead(Hall_START);//存储1号霍尔传感器的状态  END = digitalRead(Hall_END);//存储2号霍尔传感器的状态  //开始工作  if(is_free == false && is_working == true )  {      SPEED = 100;         //计数器计数,忽略第一次检测状态      if(count >500)  { MODEL = OVER; }      count++;  }  //结束工作  if (MODEL == OVER && END == 0)  {    SPEED = 0;//速度清零    count = 0;//计数器清零    is_working = false;//工作指示变量复位    is_free = true;//空闲指示变量复位    MODEL = 0;//状态复位  }  Serial.println(count);  stepper.setSpeed(SPEED);   stepper.runSpeed();}

图 44

 

至此,翻页动画显示器就全部制作完成了

 

#总结#

 

本次作品我们掌握了霍尔传感器的工作原理,学习了28BYJ-48步进电机的的使用方法,掌握了这些,更多有趣的动画内容都可以轻松展示,比如各种动漫主题的素材,那还等什么,赶快去试试吧

 

虎年春节马上就要到了,最后祝大家在新的一年虎乐安康,万事顺遂

 

造物让生活更美好,我们下期再见!