玩转树莓派

简介

Raspberry Pi 中文名为树莓派,原本是为学习计算机编程教育而设计的只有卡片大小的微型电脑,上面可以运行 Linux 甚至 Windows 10 loT 系统。树莓派虽小,却五脏俱全,而且拥有丰富的拓展接口,是学习Linux、嵌入式、物联网的利器。

开始使用

准备工具

  • 树莓派,当前最新版本是 这里使用的是树莓派3B
  • 读卡器,给树莓派烧录系统用,因为树莓派的系统安装在内存卡。
  • 最好 8G 或以上的 Micro SD 卡,但是也不用太大,否则可能不稳定甚至不支持。
  • 最好 5V 2.5A 电源(普通安卓充电器也可以),如果需要为树莓派扩展硬件的话,电源需要比较给力。
  • 鼠标、键盘、HDMI转VGA线还有显示器,不过这些并不是必须的,看情况使用。

安装系统

下载镜像包

镜像包可以选择官方的镜像,或者第三方的镜像

官方下载:https://www.raspberrypi.org/downloads/
Ubuntu:https://wiki.ubuntu.com/ARM/RaspberryPi

这里下载官方系统的Lite版,点此下载

解压和烧录

可以在Linux下和Windows下进行烧录,Windows下需要下载 Win32 Disk IMager 工具进行烧录,linux下可以直接使用dd命令。

Linux下烧录

将内存卡插入到读卡器,然后读卡器插入电脑,读卡器设备被系统映射为了 /dev/sdc

注意:Linux需要看看读卡器被系统映射为了哪个设备文件,如果指定错了设备文件,后果可能不堪设想。

1
2
3
4
# 先卸载一下 确保系统没有主动挂载这个设备,如果存在多个分区,需要卸载多个
umount /dev/sdc1
unzip 2018-04-18-raspbian-stretch-lite.zip
sudo dd if=2018-04-18-raspbian-stretch-lite.img of=/dev/sdc bs=4M

Windows下烧录

先将下载的xz镜像解压为img文件,然后使用 Win32 Disk IMager 工具烧录到内存卡。


需要注意的是,选择SD卡的设备,然后选择好解压后的img镜像后点击 write 开始写入。

启动树莓派

正常来说,插入内存卡,插入网线就可以开机了,树莓派默认会DHCP获取IP地址,但是如果局域网不存在DHCP服务,那启动后会在获取DHCP地址过程中等待五六分钟,而且这种情况没有显示器就没法操作树莓派了。

配置静态IP

但是对于不存在DHCP服务的局域网,可以在启动树莓派之前就配置好树莓派的IP地址,这样启动后就会自动应用配置的IP,连显示器和键盘也不需要了。

以下操作在 Linux 上进行。

1
2
mount /dev/sdc2 /mnt		# 烧录后树莓派的rootfs在sdc的第二个分区上
vim /mnt/etc/network/interfaces # 编辑这个文件为下面内容,将IP信息替换为合适的信息
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# Source interfaces
# Please check /etc/network/interfaces.d before changing this file
# as interfaces may have been defined in /etc/network/interfaces.d
# See LP: #1262951
# source /etc/network/interfaces.d/*.cfg
auto eth0
iface eth0 inet static
    address 192.168.2.220
    netmask 255.255.255.0
    network 192.168.2.0
    broadcast 192.168.2.255
    gateway 192.168.2.254
    # dns-* options are implemented by the resolvconf package, if installed
    dns-nameservers 119.29.29.29
    dns-nameservers 223.5.5.5

自动启动SSH服务

系统默认启动是不启动SSH服务的,所以还要修改下 rc.local 文件,将 SSH服务 在系统启动后也跟着起来。

编辑 /mnt/etc/rc.local 添加内容:systemctl start ssh.servic

开机启动

插入内存卡,连接网线,连接电源的那一刻树莓派就自动启动了。默认用户名:pi 默认密码:raspberry,ssh连接下试试吧。

系统定制

定制只能在 Linux 环境下进行,这里使用 ubuntu 16.04 64位系统。

对原始的img镜像文件进行修改定制,这样如果以后需要频繁重装系统,或者用于商业目的时,可能就有这种需求了。

安装需要的包

1
2
apt-get update
apt-get install qemu qemu-user qemu-user-static kpartx

将镜像挂在到系统目录

需要先将系统镜像映射到loop设备文件,才能正常挂载镜像文件中的分区

1
2
3
losetup /dev/loop0 2018-04-18-raspbian-stretch-lite.img
kpartx -av /dev/loop0
mount /dev/mapper/loop0p2 /mnt/

这样就将镜像的 rootfs 挂载到了 /mnt 下,系统镜像有两个分区,分别被映射为了 /dev/mapper/loop0p1 和 loop0p2, 其中loop0p1是内核存放分区,暂时是不需要的。

修改镜像中的数据

qemu 提供了一个非常有意思的功能,可以 chroot 到异构CPU的二进制组成的根文件系统中,这样就可以在 x86 上对 ARM 的根文件系统的程序做调式了。

1
2
3
4
modprobe binfmt_misc
echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-static-arm-binfmt:P' > /proc/sys/fs/binfmt_misc/register
cp /usr/bin/qemu-arm-static /mnt/usr/bin/ # 将此文件拷贝到ARM的根中
chroot /mnt/ bash

执行了 chroot 之后,如果没有报错就切换到树莓派的根文件系统了,可以看看当前根的二进制文件是不是 ARM 架构的了 file /bin/bash,或者执行 uname -a 可以看到 内核也被模拟成了 ARM 架构的。

接下来就可以进行一些安装配置和修改文件等操作了,比如修改网卡的配置文件配置一个静态的IP地址,这样启动树莓派后就可以直接连接了。接下来修改 apt 源为阿里云源,加快软件下载速度。

修改:/etc/apt/sources.list

deb http://mirrors.aliyun.com/raspbian/raspbian stretch main contrib non-free rpi

之后可以 apt-get update 然后安装需要的软件了。这时候就可以执行 systemctl enable ssh.service 命令,将SSH服务加入开机自启了。

修改完后退出了 chroot 环境,然后对 /mnt 目录进行卸载。

1
2
3
4
exit 			# 执行exit命令或者 Ctrl + d 就可以退出了
umount /mnt # 如果卸载不掉,使用 fuser -ka /mnt 强制卸载
kpartx -d /dev/loop0 # 卸载loop0中的分区映射
losetup -d /dev/loop0 # 卸载img文件和loop0的映射

刷入内存卡进行开机验证

一些不当的修改可能导致无法开机,而且一些特殊的软件包会对内核进行更改,这种情况下就无法使用这种方式定制了。建议每次修改完系统镜像后都进行一次归档保存,并且记录每次归档的修改信息,这样如果某次修改出现了问题导致无法开机,就可以回退到上一次归档的镜像而不是重头再来了。

功能和拓展

连接WiFi

树莓派3B默认是包含了WiFi和蓝牙模块的,配置连接WiFi路由器也很简单。

首先安装连接WiFi使用的程序

1
apt install wpasupplicant

连接WPA加密的WiFi

创建配置文件: /etc/wpa_supplicant/wpa_supplicant.conf

network={
        ssid="SSID"
        key_mgmt=WPA-PSK
        psk="PASSWORD"
}

SSIDPASSWORD 替换成要连接的用户名和密码就可以了。

然后执行 wpa_supplicant 命令手动连接到WiFi

1
wpa_supplicant -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf

这种方式连接WiFi 如果有错误会打印错误信息,适合手动调试WiFi,等连接无误后,ifconfig 命令可以看到 wlan0 这块网卡。这个时候还是没有IP地址的,需要手动配置一个IP地址或者使用 dhclient wlan0 命令来自动获取IP地址。

还可以让系统 networking 服务来开机自动连接,修改网卡配置文件:/etc/network/interfaces 添加以下内容

auto wlan0
iface wlan0 inet dhcp
  wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

或者配置为静态IP地址

auto wlan0
iface wlan0 inet static
    address 192.168.0.2
    netmask 255.255.255.0
    gateway 192.168.0.1
    dns-nameservers 119.29.29.29
    dns-nameservers 114.114.114.114
  wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

注意: 使用 systemctl restart networking.service 时,如果长时间没有反应,千万不要强行停止,否则可能会各种问题

连接隐藏的WiFi

修改配置文件:/etc/wpa_supplicant/wpa_supplicant.conf 为以下内容

network={
    ssid="SSID"
    scan_ssid=1
    psk="PASSWORD"
}

同理,将 SSIDPASSWORD 替换为自己实际的,其他步骤和上面的一致。

连接没密码的WiFi

修改配置文件:/etc/wpa_supplicant/wpa_supplicant.conf 为以下内容

network={
        ssid="SSID"
        key_mgmt=NONE
}

添加多个WiFi

可以在配置文件中添加多个 network 配置块来添加多个WiFi配置,wpa_supplicant 将会自动连接可以连接的WiFi,也可以手动配置优先级来偏重连接某个WiFi。

network={
    ssid="SSID1"
    psk="PASSWORD1"
    priority=1
    id_str="homeOne"
}

network={
    ssid="SSID2"
    psk="PASSWORD2"
    priority=2
    id_str="homeTwo"
}

使用4G上网

由于树莓派3B并没有自带4G模块,所以想使用SIM卡拨号上网就需要另外买一个4G模块。树莓派3B也没有适用于4G模块的 Mini PCI-e 接口,所以还需要买一个 Mini PCI-e 转 USB 的4G模块专用开发板。

这里4G模块使用 华为ME909s-821,SIM卡使用联通实名制的4G卡,需要先保证4G卡可以正常上网。

安装4G拨号软件

1
apt install wvdial

修改配置文件:/etc/wvdial.conf 添加如下内容

[Dialer wcdma]
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0
Init3 = AT+CGDCONT=1,"IP","3gnet"
Modem Type = Analog Modem
Baud = 9600
New PPPD = yes
Modem = /dev/ttyUSB0
ISDN = 0
Phone = *99#
Password = guest
Username = guest

需要注意的地方是 Modem = /dev/ttyUSB0 ,需要找到4G模块的设备文件,如果不确定4G模块的设备文件是啥,可以先记录下 /dev/ 目录下的所有文件名,然后插上后看看多出来了哪些,4G模块会多出来5个设备文件,一般第一个 ttyUSB* 设备文件是 Modem 的设备文件,也就是 /dev/ttyUSB0,但是如果已经存在了其它的 ttyUSB* 文件,则4G模块的设备文件会依次往后排。

将4G模块插入 Mini PCI-e 接口将SIM卡插入到卡槽,天线最好接上,否则信号可能太差导致拨号失败。

使用 wvdial wcdma 命令开始拨号,当出现如下信息时,则拨号成功了

--> local  IP address 10.90.80.32
--> pppd: XE[01]
--> remote IP address 10.64.64.64
--> pppd: XE[01]
--> primary   DNS address 123.123.123.123
--> pppd: XE[01]
--> secondary DNS address 123.123.123.124
--> pppd: XE[01]

这时候使用 ifconfig 可以看到 ppp0 接口已经连接

ppp0      Link encap:Point-to-Point Protocol  
        inet addr:10.90.80.32  P-t-P:10.64.64.64  Mask:255.255.255.255
        UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
        RX packets:6 errors:0 dropped:0 overruns:0 frame:0
        TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:3 
        RX bytes:66 (66.0 B)  TX bytes:129 (129.0 B)

然后替换默认路由到点对点拨号的对端IP就可以使用4G上网了

1
2
ip ro replace default via 10.64.64.6
ping www.baidu.com -c 4
root@raspberrypi:~# ip ro replace default via 10.64.64.64 
root@raspberrypi:~# ping www.baidu.com -c 4
PING www.a.shifen.com (61.135.169.121) 56(84) bytes of data.
64 bytes from 61.135.169.121: icmp_seq=1 ttl=54 time=36.2 ms
64 bytes from 61.135.169.121: icmp_seq=2 ttl=54 time=25.9 ms
64 bytes from 61.135.169.121: icmp_seq=3 ttl=54 time=21.9 ms
64 bytes from 61.135.169.121: icmp_seq=4 ttl=54 time=19.8 ms

--- www.a.shifen.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 19.859/25.984/36.220/6.300 ms
root@raspberrypi:~# 

还有一些需要注意的地方,如果使用物联网卡,需要确保物联网卡是否支持4G,是否支持数据业务,以及4G模块支持的网络和运营商。

wvdial 程序 Ctrl + c 后4G就自动断开了。

使用GPS模块

如果想用树莓派做行车记录仪之类的东西,GPS模块就必不可少了,这里使用 NEO-7N-0-002 GPS模块。
这款GPS模块支持通过USB连接到树莓派,也支持和树莓派直接进行串口连接。

USB连接

直接使用普通的数据线连接,自带陶瓷天线,但是最好外接天线。使用自带的陶瓷天线定位时最好将GPS模块放到靠窗的位置,户外效果最佳,否则将无法定位。

连接如下,通过USB连接后设备被映射为 /dev/ttyACM0

当橘红色的灯按频率闪灭,而不是常亮时就定位成功了,使用 cat /dev/ttyACM0 命令查看GPS模块的输出只需要关心 $GPGGA 的内容就可以,定位成功的信息是这样子的

root@raspberrypi:~# cat /dev/ttyACM0 |grep GPGGA
$GPGGA,025456.00,?955.49947,N,?1619.28218,E,2,08,1.52,98.4,M,-8.7,M,,0000*74
$GPGGA,025457.00,?955.49948,N,?1619.28211,E,2,08,1.52,98.5,M,-8.7,M,,0000*72
$GPGGA,025458.00,?955.49960,N,?1619.28209,E,2,08,1.52,98.4,M,-8.7,M,,0000*7F
$GPGGA,025459.00,?955.49967,N,?1619.28204,E,2,08,1.52,98.3,M,-8.7,M,,0000*73

其中 ?955.49947,N,?1619.28218,E N前面的浮点数表示北纬,E前面的浮点数表示东经,为了防止位置信息泄露,所以其中有一位数字用 ? 代替了,想了解 $GPGGA 的更多详细信息,可以翻阅 GPGGA 卫星数据格式。

串口连接

由于树莓派3B自带的串口被用于蓝牙了,所以最省事的方法就是使用USB转TTL线,将TTL线的 +5V 接到GPS模块的 VCC 引脚, GND 接到GPS模块的 GND,TXD 接到GPS模块的 RXD,RXD 接到GPS模块的 TXD,也就是说TTL线的输入输出要和GPS模块的输入输出交叉接。

但是不知道是不是这款GPS模块板子上印刷错了,导致TTL线的 RXD 必须和 GPS模块上印刷的 RXD 引脚相接才能正常接收数据,由于只需要从GPS模块上接收数据,所以TTL线的 TXD 也可以不和GPS模块相接。

接线图如下

使用 minicom -D /dev/ttyUSB0 -b 9600 命令就可以获取GPS数据了。如果要处理GPS数据,可以用程序直连串口获取。摁下 Ctrl + a 松开后摁 x 然后敲下回车就退出 minicom 了。

设备和设备文件绑定

前面的4G模块使用的是 /dev/ttyUSB0 设备文件,TTL线使用的也是 /dev/ttyUSB0,如果同时使用这两个模块,重启后谁也无法确定当前的 /dev/ttyUSB0 是哪个模块,这种情况可以使用 udev 规则来绑定设备和设备文件。

使用 udevadm info --attribute-walk --name=/dev/ttyUSB0 可以查看当前 /dev/ttyUSB0 设备的详细信息,然后通过这些信息匹配来为设备文件建立一个软连接,这样每次可以通过软连接来访问设备了。

添加文件:/etc/udev/rules.d/mydevice.rules

KERNEL=="ttyUSB*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", GROUP:="dialout",  SYMLINK+="ttl0"
KERNEL=="ttyUSB*", ATTRS{bInterfaceNumber}=="02", MODE:="0666", GROUP:="dialout",  SYMLINK+="hw4g0"
KERNEL=="ttyUSB*", ATTRS{bInterfaceNumber}=="03", MODE:="0666", GROUP:="dialout",  SYMLINK+="hw4g1"
KERNEL=="ttyUSB*", ATTRS{bInterfaceNumber}=="04", MODE:="0666", GROUP:="dialout",  SYMLINK+="hw4g2"
KERNEL=="ttyUSB*", ATTRS{bInterfaceNumber}=="05", MODE:="0666", GROUP:="dialout",  SYMLINK+="hw4g3"
KERNEL=="ttyUSB*", ATTRS{bInterfaceNumber}=="06", MODE:="0666", GROUP:="dialout",  SYMLINK+="hw4g4"

这样同时使用GPS和4G模块就可以通过访问 /dev/ttl0/dev/hw4g0 来实现了。udev 规则的编写可以执行 man udev 获取。

附录

资料参考: