前言
我一直梦想着能够做出一款自制的飞行器,然后带着它游历世界各地,拍摄各种好玩的照片。听说树莓派似乎可以将我的编程专业发挥出来,既然如此,那么就开干吧。
那么就从环境的搭建开始做起,并以此博客作为记录和总结,也方便各位树莓派以及飞行器爱好者参考和借鉴。此外,我写的代码都会公开出来,方便大家探讨。
当然,本人初学者更希望有各路大神指点指点。
树莓派(Raspberry Pi)是学习计算机知识、架设服务器的好工具,价格低廉,可玩性高。
本文根据我的亲身经验,介绍如何从零开始,搭建一个树莓派服务器,控制 LED 灯。你会看到,树莓派玩起来实在很容易。
一、型号
树莓派是一个迷你电脑,集成在一块电路板。目前,最新的型号有两个。
(1)Raspberry Pi 3代 B 型
(2)Raspberry Pi zero (含 zero w)
虽然后者便宜,但是少了许多接口(比如只有一个 USB 口),CPU 和内存都比较低,配件也少,因此推荐购买第3代的 B 型。以下都针对这个型号,但大部分内容对 zero 也适用。
二、配件
树莓派本身只是一个主机。要运行起来,必须有配件。
(1)电源
Micro USB 接口的手机充电器,就可以充当电源,但输出必须是 5V 电压、至少 2A 电流。充电宝当电源也没问题。
(2)Micro SD 卡
树莓派不带硬盘,Micro SD 卡就是硬盘。最小容量8G,推荐使用16G和32G的卡。
(3)显示器
树莓派有 HDMI 输出,显示器必须有该接口。如果有 HDMI 转 VGA 的转接线,那么 VGA 显示器也可以。我用的是一个 7 寸的液晶监视器。
不过,显示器只在安装系统时需要,后面可以 SSH登录 ,所以就不需要了。
(4)无线键鼠
树莓派内置蓝牙,USB 或蓝牙的无线键鼠都可以用。
就像显示器一样,如果树莓派已经装好系统,而且只当作服务器,无线键鼠也可以不配。
三、电子元件
除了配件,下面的实验还需要一些电子元件。
(1)面包板(一块)
(2)连接线(若干)
注意,连接线必须一端是公头,一端是母头。
另外,最好也备一些两端都是公头的连接线。
(3)LED 二极管(若干)
(4)270欧姆的电阻(若干)
四、安装系统
如果商家已经装好系统,可以跳过这一步,否则需要自己安装操作系统。
官方提供的操作系统是 Raspbian,这是 Debian 系统的定制版。
官方还提供一个安装器 NOOBS,建议通过它来安装 Raspbian,相对简单一点。
下载 NOOBS。
格式化 Micro SD 卡为 FAT 格式(操作指导)。
解压NOOBS.zip到 Micro SD 卡根目录。
插入 Micro SD 卡到树莓派底部的卡槽,接通电源,启动系统。
正常情况下,按照屏幕上的提示,一路回车,就能装好系统。
五、SSH 登录
安装系统后,树莓派就可以上网了(Wifi 或者网线)。这时,你要看一下它的局域网 IP 地址,可以使用下面的命令。
$ sudo ifconfig
然后,更改系统设置,打开 SSH 登录(默认是禁止的)。
接着,从另一台电脑 SSH 登录树莓派。下面的命令是在局域网的另一台电脑上执行的。
$ ssh [email protected]
上面代码中,192.168.1.5
是我的树莓派的地址,你要换成你的地址。树莓派的默认用户是pi
。
树莓派会提示你输入密码。pi
的默认密码是raspberry
。正常情况下,这样就可以登录树莓派了。接着,就可以进行各种服务器操作了,比如修改密码。
$ passwd
后面的实验需要将用户加入gpio
用户组。
$ sudo adduser pi gpio
上面的代码表示将用户pi
加入gpio
用户组。
六、安装 Node
为了运行 Node 脚本,树莓派必须安装 Node,可以参考这篇文章。
$ curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
$ sudo apt install nodejs
正常情况下,Node 8.x 版就已经安装成功了。
$ node -v
v8.1.0
七、点亮 LED
树莓派提供了一组对外的 IO 接口,称为 GPIO( 通用 IO 接口,General-purpose input/output)。
GPIO基本介绍
GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平。GPIO是个比较重要的概念,用户可以通过GPIO口和硬件进行数据交互(如UART),控制硬件工作(如LED、蜂鸣器等),读取硬件的工作状态信号(如中断信号)等。GPIO口的使用非常广泛。掌握了GPIO,差不多相当于掌握了操作硬件的能力。
它的 40 个脚的定义如下图。
注意,左上角的第1针(3.3V)是一个方块,其他针脚都是圆的。将树莓派翻过来,背后可以看到 GPIO 有一个角是方的,通过这种方法就可以确认哪一个针眼是3.3V。
补充: 3.3v和5v代表着该针脚会输出3.3v和5v的电压,Ground代表着该针脚是接地的,GPIO0*则是一些待用户开发的针脚。每个针脚都可以使用程序进行控制操作。ground 代表 接地。
通过 GPIO ,树莓派可以与其他电子元件连接。下面根据 Jonathan Perkin 的文章,使用树莓派连接 LED 二极管。
这里需要用到面包板。本质上,面包板就是几根导线,上面开了许多可以连到导线的孔。
+
极和-
极是两根垂直的导线,标着1
、5
、10
这些数字的行,每一行都是一根水平的导线。导线与导线之间互不连接,另外,面包板的左右两半也是互不连接的。
然后,按照下面的图,将树莓派、面包板、LED 灯、电阻连起来。
上图中,红色导线表示电流的正极,从 GPIO 的第1针(3.3V)连到面包板。黑色导线表示电流的负极,从 GPIO 第三排的第6针(ground)连到面包板。它们连到面包板的哪个眼并不重要,但必须保证能组成一个完整的电路(上图的箭头流向)。注意,LED 二极管也有正负极,长脚表示正极,短脚表示负极。电阻没有正负极。
连接完成后,打开树莓派的电源,LED 应该就会亮起来了。
八、LED 控制脚本
下面,我们使用 Node 脚本控制 LED。
首先,将正极的导线从1号针脚(3.3V)拔出,插到第6排的11号针脚(上图的 GPIO 17)。这个针脚的电流是脚本可以控制的。
然后,在树莓派上新建一个实验目录,并安装控制 GPIO 的 Node 模块rpio
。。
$ mkdir led-demo && cd led-demo
$ npm init -y
$ npm install -S rpio
接着,新建一个脚本led-on.js
。
// led-on.js
var rpio = require('rpio');
// 打开 11 号针脚(GPIO17) 作为输出
rpio.open(11, rpio.OUTPUT);
// 指定 11 号针脚输出电流(HIGH)
rpio.write(11, rpio.HIGH);
运行这个脚本,应该就会看到 LED 灯泡变亮了。
$ node led-on.js
再新建一个led-off.js
脚本,只要改一行就行。
var rpio = require('rpio');
// Configure pin 11 (GPIO17) for output (i.e. read/write).
// rpio.setOutput(11);
rpio.open(11, rpio.OUTPUT);
// 指定 11 号针脚停止输出电流(LOW)
// Turn GPIO17 off, also known as 'LOW'.
rpio.write(11, rpio.LOW);
运行这个脚本,LED 灯泡应该就会熄灭了。
$ node led-off.js
有了这两个脚本,让 LED 闪烁就轻而易举了。新建一个led-blink.js
脚本。
var rpio = require('rpio');
rpio.open(11, rpio.OUTPUT);
/*
* Blink the LED quickly (10 times per second). It is switched on every
* 100ms, and a timeout is set for 50ms later to switch it off, giving us
* the regular blink.
*/
setInterval(function blink() {
rpio.write(11, rpio.HIGH);
setTimeout(function ledoff() {
rpio.write(11, rpio.LOW);
}, 50);
}, 100);
上面的脚本让 LED 每秒闪烁10次。
$ node led-blink.js
九、HTTP 服务器
通过控制 LED 可以做很多事,比如架设一个 HTTP 服务器,每当有人访问,LED 就闪烁一下。
首先,在刚才的目录里面装一个服务器模块。
$ npm install -S server
然后,新建一个脚本server.js
。
var server = require('server');
var { get } = server.router;
var rpio = require('rpio');
rpio.open(11, rpio.OUTPUT);
function blink() {
rpio.write(11, rpio.HIGH);
setTimeout(function ledoff() {
rpio.write(11, rpio.LOW);
}, 50);
}
server({ port: 8080 }, [
get('/' , ctx => {
console.log('a request is coming...');
blink();
}),
]);
console.log('server starts on 8080 port');
运行这个脚本。
$ node server.js
然后,再打开一个命令行终端,访问8080端口,LED 就会闪一下。
$ curl http://localhost:8080
好了,今天的教程就到这里。接下来,你可以自己探索,做更多的尝试,比如写一个测试用例脚本,只要测试失败 LED 就会长亮,或者组装一个8位的加法器。
python控制GPIO(教程可能是树莓派2的引脚,自己注意一下)
想用python来控制GPIO,最便捷的办法就是使用一些python类库,比如树莓派系统本身集成的RPi.GPIO。本文详细介绍如何使用RPi.GPIO来控制GPIO。
导入RPi.GPIO模块
可以用下面的代码导入RPi.GPIO模块。
import RPi.GPIO as GPIO
引入之后,就可以使用GPIO模块的函数了。如果你想检查模块是否引入成功,也可以这样写:
try:
import RPi.GPIO as GPIO
except RuntimeError:
print("引入错误")
针脚编号
在RPi.GPIO中,同时支持树莓派上的两种GPIO引脚编号。第一种编号是BOARD编号,这和树莓派电路板上的物理引脚编号相对应。使用这种编号的好处是,你的硬件将是一直可以使用的,不用担心树莓派的版本问题。因此,在电路板升级后,你不需要重写连接器或代码。
第二种编号是BCM规则,是更底层的工作方式,它和Broadcom的片上系统中信道编号相对应。在使用一个引脚时,你需要查找信道号和物理引脚编号之间的对应规则。对于不同的树莓派版本,编写的脚本文件也可能是无法通用的。
你可以使用下列代码(强制的)指定一种编号规则:
GPIO.setmode(GPIO.BOARD)
# or
GPIO.setmode(GPIO.BCM)
下面代码将返回被设置的编号规则
mode = GPIO.getmode()
警告
如果RPi.GRIO检测到一个引脚已经被设置成了非默认值,那么你将看到一个警告信息。你可以通过下列代码禁用警告:
GPIO.setwarnings(False)
引脚设置
在使用一个引脚前,你需要设置这些引脚作为输入还是输出。配置一个引脚的代码如下:
# 将引脚设置为输入模式
GPIO.setup(channel, GPIO.IN)
# 将引脚设置为输出模式
GPIO.setup(channel, GPIO.OUT)
# 为输出的引脚设置默认值
GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH)
释放
一般来说,程序到达最后都需要释放资源,这个好习惯可以避免偶然损坏树莓派。释放脚本中的使用的引脚:
GPIO.cleanup()
注意,GPIO.cleanup()只会释放掉脚本中使用的GPIO引脚,并会清除设置的引脚编号规则。
输出
要想点亮一个LED灯,或者驱动某个设备,都需要给电流和电压他们,这个步骤也很简单,设置引脚的输出状态就可以了,代码如下:
GPIO.output(channel, state)
状态可以设置为0 / GPIO.LOW / False / 1 / GPIO.HIGH / True。如果编码规则为,GPIO.BOARD,那么channel就是对应引脚的数字。
如果想一次性设置多个引脚,可使用下面的代码:
chan_list = [11,12]
GPIO.output(chan_list, GPIO.LOW)
GPIO.output(chan_list, (GPIO.HIGH, GPIO.LOW))
你还可以使用Input()函数读取一个输出引脚的状态并将其作为输出值,例如:
GPIO.output(12, not GPIO.input(12))
读取
我们也常常需要读取引脚的输入状态,获取引脚输入状态如下代码:
GPIO.input(channel)
低电平返回0 / GPIO.LOW / False,高电平返回1 / GPIO.HIGH / True。
如果输入引脚处于悬空状态,引脚的值将是漂动的。换句话说,读取到的值是未知的,因为它并没有被连接到任何的信号上,直到按下一个按钮或开关。由于干扰的影响,输入的值可能会反复的变化。
使用如下代码可以解决问题:
GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# or
GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
需要注意的是,上面的读取代码只是获取当前一瞬间的引脚输入信号。
如果需要实时监控引脚的状态变化,可以有两种办法。最简单原始的方式是每隔一段时间检查输入的信号值,这种方式被称为轮询。如果你的程序读取的时机错误,则很可能会丢失输入信号。轮询是在循环中执行的,这种方式比较占用处理器资源。另一种响应GPIO输入的方式是使用中断(边缘检测),这里的边缘是指信号从高到低的变换(下降沿)或从低到高的变换(上升沿)。
轮询方式
while GPIO.input(channel) == GPIO.LOW:
time.sleep(0.01) # wait 10 ms to give CPU chance to do other things
边缘检测
边缘是指信号状态的改变,从低到高(上升沿)或从高到低(下降沿)。通常情况下,我们更关心于输入状态的该边而不是输入信号的值。这种状态的该边被称为事件。
先介绍两个函数:
- wait_for_edge() 函数。
wait_for_edge()被用于阻止程序的继续执行,直到检测到一个边沿。也就是说,上文中等待按钮按下的实例可以改写为
channel = GPIO.wait_for_edge(channel, GPIO_RISING, timeout=5000)
if channel is None:
print('Timeout occurred')
else:
print('Edge detected on channel', channel)
- add_event_detect() 函数
该函数对一个引脚进行监听,一旦引脚输入状态发生了改变,调用event_detected()函数会返回true,如下代码:
GPIO.add_event_detect(channel, GPIO.RISING) # add rising edge detection on a channel
do_something()
// 下面的代码放在一个线程循环执行。
if GPIO.event_detected(channel):
print('Button pressed')
上面的代码需要自己新建一个线程去循环检测event_detected()的值,还算是比较麻烦的。
不过可采用另一种办法轻松检测状态,这种方式是直接传入一个回调函数:
def my_callback(channel):
print('This is a edge event callback function!')
print('Edge detected on channel %s'%channel)
print('This is run in a different thread to your main program')
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback)
如果你想设置多个回调函数,可以这样:
def my_callback_one(channel):
print('Callback one')
def my_callback_two(channel):
print('Callback two')
GPIO.add_event_detect(channel, GPIO.RISING)
GPIO.add_event_callback(channel, my_callback_one)
GPIO.add_event_callback(channel, my_callback_two)
注意:回调触发时,并不会同时执行回调函数,而是根据设置的顺序调用它们。
综合例子:点亮LED灯
好了,上面说明了一大堆函数库的用法,那么现在就应该来个简单的实验了。这个实验很简单,点亮一个LED灯。
- 编写代码之前,首先你需要将led灯的针脚通过杜邦线连接到树莓派的引脚上,比如你可以连接到11号引脚。
- 新建一个main.py文件,写入如下代码:
import RPi.GPIO as GPIO //引入函数库
import time
RPi.GPIO.setmode(GPIO.BOARD) //设置引脚编号规则
RPi.GPIO.setup(11, RPi.GPIO.OUT) //将11号引脚设置成输出模式
while True
GPIO.output(channel, 1) //将引脚的状态设置为高电平,此时LED亮了
time.sleep(1) //程序休眠1秒钟,让LED亮1秒
GPIO.output(channel, 0) //将引脚状态设置为低电平,此时LED灭了
time.sleep(1) //程序休眠1秒钟,让LED灭1秒
GPIO.cleanup() //程序的最后别忘记清除所有资源
- 保存,并退出文件。执行
python3 main.py
,即可观看效果。Ctrl+C
可以关闭程序。
- 此外,不妨也试试其它的函数吧,增强印象。
使用PWM
这个python函数库还支持PWM模式的输出,我们可以利用PWM来制作呼吸灯效果。详情看代码:
import time
import RPi.GPIO as GPIO //引入库
GPIO.setmode(GPIO.BOARD) //设置编号方式
GPIO.setup(12, GPIO.OUT) //设置12号引脚为输出模式
p = GPIO.PWM(12, 50) //将12号引脚初始化为PWM实例 ,频率为50Hz
p.start(0) //开始脉宽调制,参数范围为: (0.0 <= dc <= 100.0)
try:
while 1:
for dc in range(0, 101, 5):
p.ChangeDutyCycle(dc) //修改占空比 参数范围为: (0.0 <= dc <= 100.0)
time.sleep(0.1)
for dc in range(100, -1, -5):
p.ChangeDutyCycle(dc)
time.sleep(0.1)
except KeyboardInterrupt:
pass
p.stop() //停止输出PWM波
GPIO.cleanup() //清除
结语
在文中,主要讲解了GPIO的概念,以及如何使用python操作GPIO。如果有条件,建议大家多动动手,你会收获不少满足感。我也是初学者,如果你有任何问题,大家一起探讨学习。
本文参考文档:https://sourceforge.net/p/raspberry-gpio-python/wiki/
本文转载自:
http://www.ruanyifeng.com/blog/2017/06/raspberry-pi-tutorial.html
http://blog.hyesheng.com/2016-09-01-raspberry02/