2016/08/31维护中,以下只是大纲和口语化记录,稍后整理详细步骤和不会卡的gif
总览
光圈机械结构
光圈是很经典的机械结构,在Instructables上搜索Iris(光圈)就能找到很多手动的光圈制作教程,叶片数也不限于12片。
如上图中的6片结构,相比12叶片的结构更容易实现,因为叶片之间并无相互重叠都在同一平面上。缺点是开合的过程中开口不是圆形的而是星形。
而我们用到的12叶片结构在视觉上效果更好,不过在建模时由于仿真软件无法模拟弹性材料,因此只能把交错重叠的叶片放在同一平面。
以上是俯视的透视线图,可以看到每个叶片其实只旋转了约90°,开口就能完全闭合(但现实情况中由于重叠交错的叶片有摩擦力,不可能做到完全闭合)。
单个叶片的结构就是在120°圆弧的两端分别有两个旋转轴,朝向相反。上端的轴在上部环形结构旋转时发生角度偏移,形成相对旋转的运动;下端的轴则固定在基座的凹糟中,除了旋转还能沿基座轴向运动,形成销槽。
可以看到光圈的内径外径需满足一定的数学关系,且需确定好两个轴的位置,才能让开口接近闭合,同时转轴的运动轨迹不会超过基座销槽的长度。
理解了光圈的结构就能很容易看懂上面的透视图了。而实际工作的烟灰缸只需让上部的环形结构由电机带动旋转即可。也就有了下方的结构图。
电机控制
这里我们使用了步进电机作为动力,特点是能精确控制旋转的角度,在这里我们需要让环形结构从0°精确旋转至90°。
确定好电机的尺寸图
然后在Auto Fusion中建模。
为了让电机正常工作,需要单独使用电机驱动板来获取Arduino发送的控制信号,并获取需要较高工作电流的电源。这里选取的工作电压是9V,步进电机单相工作电流是2A。
齿轮是另一个奇特的东西,当我们放大齿轮的细节,发现它们不是想象中简单的锯齿,而是有特别的形状,其实这些弧线都是经过计算得来的,更详细的说明参考关于齿轮
红外感应、点火模块与电路逻辑
红外开关是常见的传感器,这里使用到的红外传感器感应范围在3-40CM可调,工作电压3.3V。实际测试中发现在日光下无法正常工作,得转移至室内。或者考虑到需要像常见的遥控器一样加上一层滤光挡板。
点火模块和常见的自动防风打火机使用的模块相同,工作电压在3-5V,只是工作电流能到3-4A,因此对电源匹配要求较高。点火时间最好不超过10秒,一方面钨丝本身发热时间过长会有损耗,另一方面考虑到点火模块本身发热会导致和模块接触的外壳会熔化,因此在点火模块周围考虑选用耐热材料。
控制的部分用到了Arduino,控制逻辑也很简单,循环扫描红外开关,当检测到一次挥手,则开关烟灰缸,中间停顿2s。如果检测到两次挥手,则激活点火模块。检测挥手的灵敏度可调,这里的挥手算法考虑之后参考其他开源程序。
加工的细节
外壳采用SLA光固化3D打印,实际打印效果表面质地非常好,已经接近普通的量产产品了。只是价格非常贵,接近2元/克,因此在设计中需要注意把得实心的部分挖空,壁厚只留2mm,对于普通使用2mm足够承重了。
喷漆是门手艺活,还需要多练习。
叶片用的1mm锰钢带,线切割加工。实际测试发现叶片还是太厚了以至于可以闭合的口不够小,且表面质地不如磨砂的,不平整。如果有0.05mm会更理想,但加工难度更高,且过于薄的钢片本身会松弛,导致开口闭合时中间塌陷。考虑更改叶片结构,不使用交错重叠的方式。
源程序
#include <Stepper.h>
#define STEPS 200
const int left_infrared=8;
const int right_infrared=9;
const int standby_pin=3;
const int fire_relay=2;
const int swap_threshold=800;
// const int STEPS=200;
const int open_speed=100;
Stepper stepper(STEPS,4,5,6,7);
void setup()
{
pinMode(left_infrared,INPUT_PULLUP);
pinMode(right_infrared,INPUT_PULLUP);
stepper.setSpeed(open_speed);
pinMode(standby_pin,OUTPUT);
pinMode(fire_relay,OUTPUT);
digitalWrite(fire_relay,LOW);
digitalWrite(standby_pin,LOW);
// step(200);
// step(-200);
// Serial.begin(9600);
}
void loop()
{
// debug_mode();
// initial_position();
normal_work();
}
/////////////////////////
/////////////////////////
/////////////////////////
void step(int steps)
{
digitalWrite(standby_pin,HIGH);
stepper.step(steps);
digitalWrite(standby_pin,LOW);
}
void debug_mode(){
if(!digitalRead(right_infrared)){
stepper.step(10);
}
if(!digitalRead(left_infrared)){
stepper.step(-10);
}
}
void normal_work(){
int detect_count=0;
unsigned long time_stack=0;
while(digitalRead(left_infrared) && digitalRead(right_infrared)){
;
}
delay(50);
while(!digitalRead(left_infrared) || !digitalRead(right_infrared)){
;
}
time_stack=millis();
detect_count=1;
while((millis()-time_stack)<=swap_threshold){
if(!digitalRead(left_infrared) || !digitalRead(right_infrared)){
detect_count=2;
}
}
if(detect_count==1){open_and_close();}
else if(detect_count==2){fire();}
delay(2000);
}
void fire(){
digitalWrite(fire_relay,HIGH);
delay(7000);
digitalWrite(fire_relay,LOW);
}
void open_and_close(){
step(-780);
delay(2000);
step(780);
delay(2000);
}
void initial_position(){
delay(1000);
step(780);
delay(5000);
}