查看: 6454|回复: 27

[项目] 基于树莓派的水滴摄影控制器

[复制链接]
  • TA的每日心情
    开心
    2019-7-17 13:13
  • 签到天数: 264 天

    [LV.8]以坛为家I

    发表于 2019-3-22 00:12 | 显示全部楼层 |阅读模式
    【什么是水滴摄影】
      水滴摄影是一种细分的小众门类,就是用电子+摄影拍摄水滴的碰撞、溅落等过程。又分为透明(一般逆光拍摄)以及不透明拍摄(比如牛奶皇冠)等。捕捉水滴稍纵即逝的美好瞬间。魅力来自于从不同平常的视角观察水滴的晶莹,凝固瞬间,即便是同样的参数,由于受到很多因素的影响,也不会呈现一模一样的照片。这种不确定性本身就是一种魅力,更是在用另外的角度诠释“无常”。


    拍摄背景:近似全黑的房间。
    透明拍摄:闪光灯+柔光板正对相机镜头,水滴在两者之间,水滴在溅落、碰撞的过程中,闪光灯适时引闪,通过柔光板之后的光线将晶莹的水滴曝光在相机的CCD上。
    不透明拍摄:闪光灯与相机在一个方向,其余同上,这样在拍摄过程中,就可以得到类似牛奶皇冠这样的画面。

    问题是:怎么就正好在水滴溅落、碰撞中,闪光灯适时引闪,相机快门正好打开呢?你可以选择手动方式去控制闪灯和快门,可以想象,成功率极低、对快门损耗极大。这条路,脑补一下就可以了,不必尝试。
    方法二就是高速摄影,把整个过程拍摄下来,然后选择需要的画面,这个问题不在本文讨论中。

    我们的目的,就是做一个自动控制器,把水滴的溅落(碰撞)以及拍摄过程全程控制起来。

    【控制器的主要功能和基本原理】
    主要功能:(1)控制闪光灯引闪;(2)控制相机快门;(3)控制水滴滴落(碰撞);上述三个环节的全过程用一个流程控制。
    基本原理:
       通过单片机或者树莓派,控制电磁阀的开断(实现水滴溅落、碰撞),控制闪光灯引闪,控制快门触发。所有的人机对话、参数设置以及逻辑控制在单片机或者树莓派上完成。驱动gpio完成上述控制行为。

    【第一版、第二版回顾】
      我从2012年开始学习arduino,第一个项目就是用arduino uno制作了一个水滴控制器,用了三个电位器做参数输入,用一片1602液晶作为显示器,使用UNO作为主控。实现单电磁阀、单闪光灯的控制,拍摄出来了第一张水滴碰撞的片子。
    v1.jpg
    这个项目虽然简单,但是串联起来了输入、输出、显示、控制等所有环节,是一个非常适合初学者学习的小项目。虽然很简陋,但还是非常有效实用。

        2014年开始构思第二个版本,就是树莓派版,当时树莓派刚刚推出,我觉得非常适合用于水滴控制,于是在2016年前后,就有了第二版,树莓派1A作为主控,控制两个电磁阀和一组闪灯,当时由于我对闪灯的控制设计不够合理,试图用四个IO口控制四个闪灯,实现引闪,结果造成了闪灯之间的引闪不同步,最后投入实用的只有一组闪灯。这个控制器也给我带来了很多学习的快乐。学习了python,以及pythonGUI编程以及gpio控制。这个控制器是用洞洞板+CMOS模块来合成的,大量飞线,也造成了运行中的稳定性不足。尤其是只能控制一盏闪灯成为了硬伤。于是从2017年开始构思第三版。
    version2.jpg

    第三版的目的:
    1)控制资源扩大:控制四个闪灯、八个电磁阀以及一个快门和一个“预对焦”(唤醒相机)
    2)多线程控制,将闪灯、电磁阀、对焦唤醒以及快门控制,分别建立线程,使用多线程控制,这个提升是单片机很难做到的。优点就是逻辑非常清晰,每个控制逻辑一条线程。相对关系一目了然,不用相互折算。
    3)设计了水冲洗逻辑,在拍摄前后,对电磁阀和管路进行冲洗,利于设备保养。
    4)树莓派3(最终作品由大赛提供开发板),平板电脑远程桌面方式访问树莓派,所有的控制界面在平板上实现,玩家关注参数设置以及拍摄过程,对于控制过程完全不必关注。
    v3.jpg


    【控制器硬件准备】
    内容
    数量
    1
    树莓派3
    1
    2
    控制器PCB(自制)
    1
    3
    ULN2803
    2
    4
    TLN-521-4
    2
    5
    三极管S8050
    2
    6
    电阻(1K,110OM
    3/6

    Schematic_drip2.0_Sheet.png

    PCB板)
    pcb.png

    使用sprint lyout 6.0绘制pcb,输出光绘图后,交TB打板。黑色一共打了10片。


    【软件准备】
    内容
    备注
    1
    树莓派官方系统
    2018-06-27-raspbian-stretch
    2
    Tkiner
    3
    Wxpython
    4
    RPi.GPIO

    【代码及注释】
    代码一:drip代码
    [mw_shl_code=python,true]# -*- coding=utf-8 -*-
    __author__ = 'sebnil'
    #coding utf-8
    '''
    项目名称:树莓派3B(摄影水滴控制器的第二版(多线程控制四只电磁阀,带相机唤醒)
    基本情况:GUI界面,设置五只电磁阀释放水滴以及间隔时间,控制闪光灯(四只)以及相机快门
    软件工具:wxFormBuilder/wing 101/wxpython/gpio的python RPI.GPIO官方库0.6.2
              使用wx.MilliSleep(),尝试毫秒级延时
              threading--多线程控制,从第一版的单线程扩展,每个电磁阀以及闪灯、快门,一共8个线程,并行调度控制,同一个时间轴
    硬件:RASPBERRY PI 3B//电磁阀五只,闪光灯四只,ULN2803 TLN-521-4
    V0.23: 实现8个线程、同一时间轴控制四只电磁阀以及闪灯、快门,并且唤醒相机,五只电磁阀,实现两喷+三滴
    date:2018-10-13
    变量:
    游客,如果您要查看本帖隐藏内容请回复

                    dcf1 = 18#对应电磁阀1--GPIO18
                    dcf2 = 23#对应电磁阀2--GPIO23
                    dcf3 = 24#对应电磁阀3--GPIO24
                    dcf4 = 25#对应电磁阀4--GPIO25
                    dcf5 = 12 #对应电磁阀5--GPIO12
                    flash1= 17 #闪光灯1,2,3,4---GPIO17
                    door= 5 #快门---GPIO5
                    call=13 #唤醒---GPIO13
                    GPIO.setmode(GPIO.BCM)
                    #设置OUTPUT状态
                    GPIO.setup(dcf1, GPIO.OUT)
                    GPIO.setup(dcf2, GPIO.OUT)
                    GPIO.setup(dcf3, GPIO.OUT)
                    GPIO.setup(dcf4, GPIO.OUT)
                    GPIO.setup(dcf5, GPIO.OUT)
                    GPIO.setup(flash1, GPIO.OUT)
                    GPIO.setup(door, GPIO.OUT)
                    GPIO.setup(call, GPIO.OUT)
    '''
    import wx
    import mthreadgui #mthreadgui.py就是使用wxFormBuilder写的界面描述
    import time
    import RPi.GPIO as GPIO #树莓派GPIO库
    import threading #多线程库
    from time import ctime
    from datetime import datetime

    class MyWin(mthreadgui.MyWin):
            def __init__(self, parent, title):
                    mthreadgui.MyWin.__init__(self, parent)        
            def on_button_click_event( self, event ):#OK按钮
                    global flash1,door,call
                    #初始化GPIO口
                    dcf1 = 18#对应电磁阀1--GPIO18
                    dcf2 = 23#对应电磁阀2--GPIO23
                    dcf3 = 24#对应电磁阀3--GPIO24
                    dcf4 = 25#对应电磁阀4--GPIO25
                    dcf5 = 12#对应电磁阀5--GPIO12
                    flash1= 17 #闪光灯1,2,3, 4---GPIO17
                    door= 5 #快门---GPIO5
                    call=13 #唤醒--GPIO13
                    GPIO.setmode(GPIO.BCM)
                    #设置OUTPUT状态
                    GPIO.setup(dcf1, GPIO.OUT)
                    GPIO.setup(dcf2, GPIO.OUT)
                    GPIO.setup(dcf3, GPIO.OUT)
                    GPIO.setup(dcf4, GPIO.OUT)
                    GPIO.setup(dcf5, GPIO.OUT)
                    GPIO.setup(flash1, GPIO.OUT)
                    GPIO.setup(door, GPIO.OUT)
                    GPIO.setup(call, GPIO.OUT)
                    #设置多线程,电磁阀1~5,闪灯、快门
                    threads = []
                    t1 = threading.Thread(target=fun_drip,args=(self.drip11.GetValue(),self.drip12.GetValue(),self.drip13.GetValue(),self.drip14.GetValue(),dcf1)) #电磁阀1线程
                    threads.append(t1)
                    t2 = threading.Thread(target=fun_drip,args=(self.drip21.GetValue(),self.drip22.GetValue(),self.drip23.GetValue(),self.drip24.GetValue(),dcf2)) #电磁阀2线程
                    threads.append(t2)
                    t3 = threading.Thread(target=fun_drip,args=(self.drip31.GetValue(),self.drip32.GetValue(),self.drip33.GetValue(),self.drip34.GetValue(),dcf3)) #电磁阀3线程
                    threads.append(t3)
                    t4 = threading.Thread(target=fun_drip,args=(self.drip41.GetValue(),self.drip42.GetValue(),self.drip43.GetValue(),self.drip44.GetValue(),dcf4)) #电磁阀4线程
                    threads.append(t4)
                    t5 = threading.Thread(target=fun_drip,args=(self.drip51.GetValue(),self.drip52.GetValue(),self.drip53.GetValue(),self.drip54.GetValue(),dcf5)) #电磁阀5线程
                    threads.append(t5)
                    t6 = threading.Thread(target=fun_flash,args=(self.t_flash.GetValue(),)) #闪灯线程
                    threads.append(t6)
                    t7 = threading.Thread(target=fun_shutter,args=(self.t_shutter.GetValue(),)) #快门线程
                    threads.append(t7)
                    t8 = threading.Thread(target=fun_call,args=(self.t_call.GetValue(),)) #唤醒线程
                    threads.append(t8)
                    #组装并且激活各线程
                    for t in threads:
                        t.setDaemon(True)
                        t.start()
                    for t in threads:
                        t.join()
                    print "all over %s" %ctime()
                    GPIO.cleanup()  #GPIO设置清除释放,这一条很重要
                   
    def fun_drip(delta1,delta2,delta3,delta4,dcf):
            start = datetime.now()
            #延时delta1
            wx.MilliSleep(delta1)
            #第一滴水,尺寸delta2
            GPIO.output(dcf, GPIO.HIGH)
            wx.MilliSleep(delta2)
            GPIO.output(dcf, GPIO.LOW)
            #延时delta3
            wx.MilliSleep(delta3)
            #第二滴水,尺寸delta4
            GPIO.output(dcf, GPIO.HIGH)
            wx.MilliSleep(delta4)
            GPIO.output(dcf, GPIO.LOW)
            end = datetime.now()
            delta = end-start
            print "set"
            print delta1+delta2+delta3+delta4
            print "value"
            print delta.microseconds/1000

    def fun_flash(delta5):#闪灯引闪函数
            #延时delta5毫秒
            wx.MilliSleep(delta5)
            #闪灯打开
            GPIO.output(flash1, GPIO.HIGH)
            #GPIO.output(flash2, GPIO.HIGH)
            #GPIO.output(flash3, GPIO.HIGH)
            #GPIO.output(flash4, GPIO.HIGH)
            wx.MilliSleep(100)  #保持固定脉冲100ms
            GPIO.output(flash1, GPIO.LOW)
            #GPIO.output(flash2, GPIO.LOW)
            #GPIO.output(flash3, GPIO.LOW)
            #GPIO.output(flash4, GPIO.LOW)        
            print "flash %s" %ctime()

    def fun_shutter(delta6):#快门函数
            #延时delta6毫秒
            wx.MilliSleep(delta6)
            #打开快门,我们设置快门时间0.4S,足够完成这一动作
            GPIO.output(door, GPIO.HIGH)
            wx.MilliSleep(100)#固定延时100ms给快门
            GPIO.output(door, GPIO.LOW)
            print "shutter %s" %ctime()

    def fun_call(delta7):#唤醒函数
            #延时delta7毫秒
            wx.MilliSleep(delta7)
            GPIO.output(call, GPIO.HIGH)
            wx.MilliSleep(100)#固定延时100ms给唤醒
            GPIO.output(call, GPIO.LOW)
            print "call %s" %ctime()

    # Create wxpython app
    class MyApp(wx.App):
        def OnInit(self):
            self.frame = MyWin(None, "        RPI-3B-Drop Control V0.23")
            self.SetTopWindow(self.frame)
            self.frame.Show(True)
            print("wxApp created.")

            return True

    if __name__ == "__main__":
        app = MyApp(redirect=False) # do not redirect stdout to the gui
        app.MainLoop() # render gui continuously[/mw_shl_code]



    【装配过程】
    1、焊接:PCB打板回来后,将元器件一一焊接,因为都是直插件,所以没有焊接难度。
    2、连接电磁阀、快门以及闪光灯(永诺560/四只)。
    3、装配整个拍摄体系。其中支架部分的设计,来自于高速水滴摄影群的林师兄。

    【拍摄过程】
    Step1: 设置参数,本控制器目前可以控制每个电磁阀的两次开闭,这样就是可以出两个水滴。设置电磁阀开关时间就是设置水滴大小。设置闪灯触发时间,就是设置感光的时间,这个参数不同会影响到水滴在不同阶段曝光。
    控制界面.png
    Step2器材摆放及对焦。屋子在全黑条件下,配置好闪灯位置以及水滴装置、相机位置。可以用一个棒状物在水滴滴落下来的路线上进行对焦。一个一个电磁阀进行调试,不要急于碰撞,先把每一个电磁阀的滴落以及曝光调出来。注意:即便是一模一样的参数,在室温、水的粘稠度、拍摄时间等因素不同的情况下,效果完全不一样,同样的参数,在拍摄时很难简单套用,这一点很麻烦,也是魅力所在。
    Step3:拍摄,这个环节漫长和充满期待甚至挫折。我一般都会拍摄2~3小时,甚至曾经拍摄过一个通宵。每次拍摄后,都建议看一下片子,找出存在的问题,及时调整。所以我觉得很有必要在下一个版本中,对拍摄出来的结果立即在PC中显示,避免出现错误不能发现,浪费了时间和器材。

    【注意事项】
    1、关于距离设置:在四只闪光灯灯情况下,闪灯与柔光板之间距离约为60cm,柔光板至水滴之间约为65cm。要想让画面柔和,光线摄入也应该尽可能小。这就是为什么要用多灯+柔光板(保持足够距离)+小光圈,如果光线强烈,就会造成画面锐利和玻璃感。
    2、关于光圈设置:小光圈(小于F22)。
    3、关于快门速度:使用熟练后,完全可以缩短,比如我现在一般就用1.0S左右,刚开始使用的B门(黑暗常开)。
    4、关于水滴增稠剂:一是瓜儿豆胶比较常用,二是TB有一种食物增稠剂,价廉物美,配出的水清澈透明无杂质,根本也不用过滤,粘度也比较好,长时间保存不变质,碰撞后也不易出现微小的空气泡,个人觉得比瓜胶好用。用量也不多,3-4g/1000ml左右。唯一不方便的是,不是十分溶于水,搅拌时间较长,一旦完全溶解,十分清澈,感觉就像甘油兑的一样。搅拌建议用食物料理机来搅拌,人工搅拌工作量很大而且效果达不到要求。

    【小结】
    这个控制器是我从2012年接触arduino时的第一个作品,也是一个实用器,伴随我一路而行。有了第二版、第三版。
    在制作控制器的过程中,学习了arduino的编程,学习了树莓派、debian基础知识以及python的gui和gpio控制编程。如果说这些知识点都是宝贵的
    珍珠,那么这个小小的控制器就是串起珍珠的一根银线。

    注:控制器本身并不复杂,但是高速水滴摄影是一个比较复杂的体系,建议作为进阶爱好来尝试。如果有兴趣的玩家可以去高速水滴拍摄群进行交流。


    【鸣谢】
    • 首先致谢、致敬的是林师兄(cadboy),他是一位软硬件技术非常全面的香港的工程师,从3D建模、摄影到单片机控制,无所不精。但又是一名非常有爱心、无私宽容、甘于奉献和分享的师兄。和林师兄学习的过程,本身也是一个向他学习做人、被他人格魅力感染、洗涤的过程。在此对师兄表达深深敬意,毫不夸张地说,没有林师兄的指导,不会有今天的第三版树莓派控制器和大家分享。
    • 其次致谢高速摄影群的各位师兄,不胜枚举、一并鞠躬致谢。
    • 感谢Arduino.cn提供平台,感谢孝肃师兄一直鼓励我整理这个项目,和更多同好分享。
       水滴摄影让我感受瞬间凝固的魅力,让我感受因缘无常的变幻。也让我思考和明了:唯一不变的就是变化本身。我的拍摄对象,她们的状态往往只能存在千分之一秒,每一幅美丽的水滴背后,又是多少因缘和合而成?相对于岁月长河,你可以领悟她们和钻石并无分别。
       通过水滴摄影,你可以观察到一颗水滴的兴起、碰撞、绚烂和湮灭。实际在这样的一个瞬间,你有幸观察到了一个水滴的一生。

    珍惜当下每一个时刻,不惊不畏。
    沧海抱拳。


    控制器3.0.jpg

    2016.jpg
    2016_2.jpg
    分享源代码,如果引用请注明出处。

    code_upload.rar (7.99 KB, 下载次数: 14)
  • TA的每日心情
    擦汗
    2019-1-26 16:31
  • 签到天数: 446 天

    [LV.9]以坛为家II

    发表于 2019-4-7 23:46 | 显示全部楼层
    项目请尽快更新哈~
  • TA的每日心情
    开心
    2019-7-17 13:13
  • 签到天数: 264 天

    [LV.8]以坛为家I

     楼主| 发表于 2019-4-26 00:07 | 显示全部楼层
    syl312 发表于 2019-4-7 23:46
    项目请尽快更新哈~

    4月25日已更新。剩余部分将按期完成。
  • TA的每日心情
    开心
    2019-7-17 13:13
  • 签到天数: 264 天

    [LV.8]以坛为家I

     楼主| 发表于 2019-6-20 23:34 | 显示全部楼层
    增加了PCB光绘图纸以及亚克力顶盖图纸分享。
    drip_top_0310.rar (11 KB, 下载次数: 10)
  • TA的每日心情
    无聊
    2020-5-11 15:55
  • 签到天数: 107 天

    [LV.6]常住居民II

    发表于 2019-7-6 13:15 | 显示全部楼层
    漂亮漂亮,厉害厉害。顶!
  • TA的每日心情
    开心
    2019-10-11 18:47
  • 签到天数: 38 天

    [LV.5]常住居民I

    发表于 2019-7-6 16:32 | 显示全部楼层
    感谢楼主的分享。这是我看到的最牛的水滴拍摄装住贴了。
  • TA的每日心情
    开心
    2019-10-11 18:47
  • 签到天数: 38 天

    [LV.5]常住居民I

    发表于 2019-7-8 18:20 | 显示全部楼层
    本帖最后由 njdj 于 2019-7-8 18:22 编辑

    老师您好!看了您的帖子后我也想弄一个您那样的水滴拍摄装置,只是我对树莓派的编程一窍不通,只有电子制作的能力,也能看懂电子电路图,电脑的操作也可以。您可以给我一些帮助指导吗?
  • TA的每日心情
    开心
    2019-7-17 13:13
  • 签到天数: 264 天

    [LV.8]以坛为家I

     楼主| 发表于 2019-7-13 10:20 | 显示全部楼层
    njdj 发表于 2019-7-8 18:20
    老师您好!看了您的帖子后我也想弄一个您那样的水滴拍摄装置,只是我对树莓派的编程一窍不通,只有电子制作 ...

    看得出您有一定的电子基础,当然愿意共同和您研究。
    由于参赛和篇幅所限,这次写的重点是控制器。实际上如果希望能够拍摄出漂亮的碰撞照片,还需要有摄影以及一点点机械知识(需要装配一个拍摄框架以及电磁阀等)。这个项目的难度属于进阶难度。树莓派做控制器,主要是利用其gui界面开发的便捷性以及直接驱动gpio的能力,不需要配置很高的树莓派,你可以入手。

    只要有热情,就没有什么挡得住的。另外,还有就是时间。你需要准备好这两样。
  • TA的每日心情
    开心
    2019-10-11 18:47
  • 签到天数: 38 天

    [LV.5]常住居民I

    发表于 2019-7-13 19:01 | 显示全部楼层
    沧海笑1122 发表于 2019-7-13 10:20
    看得出您有一定的电子基础,当然愿意共同和您研究。
    由于参赛和篇幅所限,这次写的重点是控制器。实际上 ...

    感谢老师的回复!我就是不懂您的这个树莓派是靠什么与平板连通上并控制的。还有平板上的控制软件是什么?树莓派我现手头上还没有(想了解以后就请教老师买一个)。我下载了您帖子里提供的压缩文件,以及您所编的代码。但是不知道它们在您设计的这个拍摄系统中是起什么作用的?
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    热门推荐

    5分钟带你快速了解新一代开发板:M5STACK
    5分钟带你快速了解新一代
    一、什么是M5Stack M5Stack是一种模块化、可堆叠扩展的开发板,每个模块
    创客火首发无人机编队套装,开启不一样的人工智能教育
    创客火首发无人机编队套装
    2017年国务院发布《新一代人工智能发展规划》,提出要广泛开展人工智能科普活动,在中
    求解用arduino 让WS2812全灯带无特效常亮并做呼吸灯效果
    求解用arduino 让WS2812全
    本人小白,初学arduino,一边逛论坛一边看网上视频教程,看得比较杂 找了很久也没找
    Arduino物联网开发实例教程
    Arduino物联网开发实例教
    [md] **blinker用户交流群 301438087 (仅限github已Star的用户加群)** ## bli
    萌新求助,小爱语音控制8266没有反应
    萌新求助,小爱语音控制82
    看了有大佬做的远程开机,就想自己试试,我用的是esp8266 nodemcu。程序烧进去以后,
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   
    快速回复 返回顶部 返回列表