树莓派监控摄像头制作

  前段时间买了台小主机,替换树莓派做云盘 / 下载器,也安装了 jellyfin 和 aria2 等其他自建服务,性能比树莓派强很多。于是树莓派又吃灰了,这次用它做个监控摄像头。

外观

点击重试外观

演示

制作

  制作过程我没有记录下来,需要的物品如下:

  • 树莓派 x1
  • 树莓派专用摄像头 x1
  • MG995 舵机 (180 度) x2
  • 雪糕棍若干
  • 热熔胶枪 + 热熔胶棒
  • 5v 电源 + 杜邦线若干

  用外接电源给两个舵机供电,需要注意的是外接电源和树莓派必须共地,否则 PWM 不会起作用。两个舵机的信号线接树莓派 gpio 的 16 和 18 个针。

代码

  详细代码在 Github 仓库。前端用的 react,后端是 fastapi 起服务,RPI.GPIO 控制 PWN,picamera 控制摄像头。用 websocket 保持连接。   支持多个终端同时观看:

# 输出
output: StreamingOutput

@app.get("/stream/{pwd}")
async def stream(pwd, background_tasks: fastapi.background.BackgroundTasks):
    # 校验密码
    check = check_pwd(pwd)
    if check:
        return check
    # 做一个generator,用于自主控制关闭
    def streamer():
        while True:
            with output.condition:
                # picamera输出,参考的官方示例,此处省略
                output.condition.wait()
                frame = output.frame
                yield (b'--FRAME\r\n' + b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
    g = streamer()
    # http断开时,关闭generator,防止卡死
    background_tasks.add_task(lambda g: g.close(), g)
    return StreamingResponse(g, media_type="multipart/x-mixed-replace;boundary=FRAME")

  python 的 asyncyield 还是比较令人费解的,我研究了很久 fastapi 如何支持多个 http stream 连接,一开始只能一个连接,而且服务端会被 block。查了一些资料,StreamingResponse 既可以异步,也可以多线程,把 def streamer() 前面的 async 去掉就行了。   background_tasks.add_task(lambda g: g.close(), g) 在连接断开时关闭 generator。相比于 flask 把所有连接都当子线程处理 (个人猜测),async 的方式明显更好,用户可以自己控制异步还是多线程。

  树莓派最近涨价地厉害,苦了爱折腾的人。虽然这个监控摄像头没啥用,而且花了好几天时间,但自己动手,完成后的小小成就感还是挺让人满足的sticker

评论