从零打造树莓派家庭监控 (一): 伺服电机控制

January 19, 2020
Python树莓派家庭监控项目

现在很多家庭喜欢购买一个摄像头来监控家里的情况,但是往往却无法了解购买第三方摄像头的安全性,摄像头泄露的新闻也每过一段时间就会出现在人们的视野当中。如果购买的摄像头拥有云端查看的功能,那么摄像头录制下来的内容肯定是要上传到摄像头的厂商的服务器上的,这其中的安全性和厂商是否会去看你的数据,就完全取决于道德了。

米家的摄像头前几天也报出了安全问题,会随机显示陌生人家里的串流,不过问题倒是很快得到修复了已经。

Google shuts down Xiaomi access to Assistant following Nest Hub picking up strangers’ camera feeds (Update: Fully resolved)

请不要评论什么废旧的手机下一个 App 也能做监控什么什么的,我都知道,我写这些文章只是为了记录一下自己曾经玩过树莓派。这个树莓派是高中的时候买的,一直吃灰没怎么用,本科的时候用 Arduino和其他嵌入式平台更多一些。。。

这一系列文章将会去手动实现一个监控系统,使用两个电机来控制摄像头的角度,并且使用一个 iPhone 的客户端来操作。所以会分成三个部分,看懂这些文章需要基 Python 基础,iOS 开发基础和电学基础。

  • 伺服电机控制
  • 摄像头监控的实现
  • 前后端的开发
  • 树莓派的Linux基础,会使用ssh之类的

这个项目的服务端和iOS客户端可以去我的 GitHub 直接下载
GitHub - Yigang0622/Home_CCTV_Server: Home CCTV Server using Raspberry Pi
GitHub - Yigang0622/Home_CCTV_iOS: 家庭监控iOS端

完成之后大概下面这样:

用到的设备

  • 树莓派,任何版本都是有 GPIO 的所以没有限制,比如我就是使用高中时候买的第一代版本
  • 伺服电机,市面上的所有型号都可以,我个人使用的是两个MG996伺服电机
  • 面包板和杜邦线,其实线不多或者不组并联的话可以不要面包板
  • USB摄像头,多年前100多买过一个微软的
  • 一堆铁架子用来放置电机

电路连接

下图是整个工程的一个电路连接,因为我需要让两个伺服电机共享一个 5V 供电和GND所以用到了面包板,两个伺服电机的控制脚位分别连接了树莓派的第18号和第21号GPIO控制接口。

点击这个链接可以下载 fritzin 的设计图

PWM控制伺服电机

伺服电机的控制方式为 PWM,PWM的全称为脉冲宽度调制,是一个模拟信号的调制方式,通过控制设备脉冲信号的占空比(duty cycle)来达到调整的目的,这个调整在这里代表伺服电机的角度。

PWM在电路中的应用很多,手机方向的极客们可能听说过 PWM 调光,利用了人眼的视觉暂留,通过调整手机背光的脉冲占空比来达到调整手机屏幕亮暗的目的。因为我不想去介绍PWM太多所以想要深入了解的话还是请上完搜索相关知识。

图源:PWM和DC这两种屏幕调光方式究竟是怎么回事-电子发烧友网

下图是伺服电机的PWM占空比示意图,首先伺服电机的工作频率是 50 Hz,也就是说信号的一个周期是 20ms,在这20ms中如果产生了一个 1ms的脉冲,那么电机将会转动到0角度(占空比为 1ms/20ms = 2%),1.5ms的脉冲则会转到90度 (7.5%占空比),2ms为180度(10%占空比)。

图源: Controlling Servo Motor with Stm32f103 microcontroller using stm32cubemx code configurator by STMicroelectronics and keil uvision 5 ide for cortex m1 series microcontrollers

点击这个链接可以下载一份MG996伺服电机的 datasheet MG996,通过查看datasheet可以看到5V是这个电机可以工作的电压,并且工作频率是 50Hz。

不过MG996的占空比似乎和上图的不太一样,通过我的实验我调整控制参数为如下:

  • 工作频率是 50 Hz
  • 2.5% 占空比为0度
  • 7.5% 占空比为90度
  • 12.5% 占空比为180度

可是如何让电机转到某个除了0,90,180之后的任何角度呢?通过上面的参数不难看出来转过的角度和占空比之间是一个一次函数的关系。 占空比为2.5的时候角度为0,占空比为12.5的时候角度为180,看起来是一个截距为2.5的一次函数呢。有了这个关系开发Python程序就很简单了。

代码实现

这段代码使用了树莓派的GPIO库所以只有在树莓派上可以跑起来,建议SSH连接树莓派用VIM做调试,因为我那个第一代树莓派用图形界面实在是卡的生活不能自理。

下面是 MyServo 伺服电机控制类的代码,没多少,很容易看懂,构造函数传入的pin为树莓派的控制引脚,default_postion 为初始化后的角度。

  1. 我设置了两个变量a和b来当做一次函数的两个参数
  2. 设置pin的GPIO为输出模式,然后初始化pin为PWM模式
  3. 开始使用 PWM 控制设备,初始占空比为 2.5%
  4. reposition函数会根据传入的角度计算出来占空比然后改变当前pin的占空比使伺服电机转向
  5. reset函数会把磁浮电机复位到开始设置的默认角度
  6. release用于释放当前pin的资源,销毁的时候会用到
  1. import RPi.GPIO as GPIO
  2. import time
  3. GPIO.setwarnings(False)
  4. class MyServo(object):
  5. """docstring for MyServo"""
  6. def __init__(self, pin, default_postion=0):
  7. #1
  8. self.b = 2.5
  9. self.a = 10
  10. self.pin = pin
  11. self.frequency = 50
  12. self.default_postion = default_postion
  13. #2
  14. GPIO.setmode(GPIO.BCM)
  15. GPIO.setup(pin, GPIO.OUT)
  16. self.pwm = GPIO.PWM(pin, self.frequency)
  17. #3
  18. self.pwm.start(2.5)
  19. print("伺服电机PIN", self.pin, '初始化')
  20. print("PWM频率", self.frequency)
  21. self.reset()
  22. #4
  23. def reposition(self,angle):
  24. if angle < 0 or angle > 180:
  25. print("Invalid position angle,", angle)
  26. return
  27. duty_cycle = self.b + self.a*(angle/180)
  28. self.pwm.ChangeDutyCycle(duty_cycle)
  29. #5
  30. def reset(self):
  31. print("电机PIN",self.pin,"复位")
  32. self.reposition(self.default_postion)
  33. #6
  34. def release(self):
  35. print("伺服电机",self.pin,"释放")
  36. self.pwm.stop()

有了上面的代码之后控制伺服电机就变得很简单了,只需要使用MyServo类的实例即可

  1. #初始化pin18和23的两个伺服电机为s0和s1
  2. s0 = MyServo(18)
  3. s1 = MyServo(23,default_postion=90)
  4. #分别控制s0和s1转向
  5. s0.repostion(90)
  6. s1.repostion(180)

稳定性

有了上面的代码,似乎你就可以控制无限数量的伺服电机,毕竟MyServo类是个对象啊,这似乎是面向对象的强项,但是在现实中效果可能并不是那么好了,当我接入了两个伺服电机和摄像头之后,伺服电机变得异常不稳定,旋转到特定角度之后还会晃动半天,我开始以为是树莓派供电不是很足,后来才知道可能是因为树莓派的 PWM 控制方式是软件 PWM 的缘故。

要改进这个现象,可以使用硬件 PWM。在别人的文章 树莓派PWM控制舵机的两种方式 – 八色木 上我得知可以使用 PCA9685 芯片来构建硬件 PWM,9685 通过 I2C 来进行通讯,可以同时生成16个PWM信号,所以对于需要多个 PWM 控制的应用,我推荐使用这个芯片来弥补软件 PWM 的不稳定。刚好树莓派也有 I2C的控制引脚。

我本身是可以通过软件来解决这个问题的,可以在每次转动到指定角度之后就关闭 pwm,每次要转动的时候再次重新开启 pwm 应该就可以了,不过没有什么意义,因为官方的 PWM 库本身也不希望那么做吧,况且只用15块钱就能得到更稳定的性能而且不用写多余的代码,何乐而不为呢?

Comments

作者
July 21, 2018 at 10:52 am

There are no comments

keyboard_arrow_up