0%

树莓派 用led制作呼吸灯

前面我们做了第一个实验,让树莓派点亮了一个小灯–点击查看,今天我们通过树莓派GPIO引脚的pwm功能来实现一个呼吸灯的效果。

准备工作

硬件器材:

  • led小灯(我选用的是红色)
  • 1kΩ电阻(保护电路)
  • 面包板一个
  • 导线若干
  • 树莓派一个

软件:

  • python2.7
  • RPi扩展库

关于pwm

PWM就是脉冲宽度调制,也就是占空比可变的脉冲波形。PWM是一个非常巧妙的技术,该技术在保持每秒脉冲个数不变的条件下允许你改变脉冲的长度。在使用之前需要先导入RPi库:

1
import RPi.GPIO as gpio

创建一个pwm实例:

1
pwm = gpio.PWM(channel, fequency)

channel为绑定的引脚,frequency为pwm的频率。

启用pwm:

1
pwm.start(dc)

dc代表占空比,范围为0.0 <= dc >= 100.0

更改频率:

1
pwm.ChangeFrequency(freq)

freq为设置的新频率,单位为Hz。

更改占空比:

1
pwm.ChangeDutyCycle(dc)

dc为设置的新的占空比。

停止pwm:

1
pwm.stop()

注意:如果实例中的占空比超出范围,也会导致pwm停止。

开始

我们继续使用BCM编码的18号引脚,创建一个文件led_breath.py,然后开始我们的代码编辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# coding: utf-8
# python 2.7
import RPi.GPIO as gpio
import time
gpio.setmode(gpio.BCM)
gpio.setup(18, gpio.OUT)
pwm_led = gpio.PWM(18, 500)
pwm_led.start(0)
print 'pwm start'
try:
while True:
for i in range(0, 100):
pwm_led.ChangeDutyCycle(i)
time.sleep(0.05)
for i in range(100, 0):
pwm_led.ChangeDutyCycle(i)
time.sleep(0.05)
except KeyboardInterrupt:
pwm_led.stop()
gpio.cleanup()
print 'pwm stop and gpio clean up by ctrl + c'

我们打开了18号gpio引脚,然后设置了一个死循环,让灯一个亮灭为周期,当按下ctrl+c的时候关闭pwm并清理gpio。

运行这个脚本:

1
$ python led_breath

如果没什么特殊情况就可以看到led灯在一亮一灭之间不停转换。

但是,这个呼吸灯有点生硬啊,因为它的变化是线性的。。。那我们能不能改进下我们的程序,让呼吸灯”呼吸“更好看一点呢?

使用三角函数

回想一下我们的三角函数,正好是在周期变化的曲线,我们来尝试使用三角函数优化下我们的led的”呼吸“效果。三角函数曲线:
三角函数曲线
对于三角函数的学习可以参考我以前的博客:三角函数

我们来观察下sin函数曲线,sin函数的值的范围在[-1, 1]区间。我们需要让它在区间[0, 100]之间那么只需要:(sinθ + 1) / 2 * 100。这样变化后,我们还需要在角度为0的时候,让y值为0,那么需要将x轴后移0.5 π个周期,即(sin(θ - 0.5 * π) + 1) / 2 * 100,我们这里θ是角度,还需要转换为弧度:rand = θ * 2 * π / 360,带入可得最后的公式:

1
y = (sin(θ * 2 * π / 360 - 0.5 * π) + 1) / 2 * 100

在python中我们使用sin函数和π,我们需要引入库:math

1
from math import sin, pi

即我们推导出的公式的python写法:

1
duty = (sin(angle * 2 * pi / 360 - 0.5 * pi) + 1) / 2 * 100

简化一下可得:

1
duty = (sin((angle / 180.0 - 0.5) * pi) + 1) * 50 

注意:python里面两个整数相除还是整除,所以这里需要给180加上小数点:180.0

好了,最终我们的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# coding: utf-8
# python 2.7
import RPi.GPIO as gpio
from math import sin, pi
import time
gpio.setmode(gpio.BCM)
gpio.setup(18, gpio.OUT)
pwm_led = gpio.PWM(18, 500)
pwm_led.start(0)
print 'pwm start'
try:
while True:
for angle in range(0, 360, 1):
duty = int((sin((angle / 180.0 - 0.5) * pi) + 1) * 50)
pwm_led.ChangeDutyCycle(duty)
time.sleep(0.003)
except KeyboardInterrupt:
# 按下ctrl+c结束进程
pwm_led.stop()
gpio.cleanup()
print 'pwm stop and clean up!'

最后看看效果:
led呼吸灯效果


通过这个例子可以对pwm有个大致了解,对后续的控制电机有很大的帮助。

码字辛苦,打赏个咖啡☕️可好?💘