树莓派提高实时性的几种方式(使用python测试)

前言

本文基于python3.5+, 树莓派型号为3b+

1. 关于树莓派的实时性

2. 几种思路与实现

2.1 提高优先级

提高优先级可以通过wiringpi库提供的piHiPri(pri)方法实现
其中,pri为int类型,取值范围为[0,99], 根据python中的实际测试,0为默认值,1优先级最高,99最小(此处貌似和资料不一致,但是实际测试是这样),使用方法为在执行前调用piHiPri()方法,具体代码如下:

import wiringpi
wiringpi.piHiPri(pri)

2.2 绑定CPU

绑定cpu需要两个操作:

  • 在系统中屏蔽掉一个或多个cpu
  • 代码中绑定cpu

屏蔽cpu的实现方法:
/boot/cmdline.txt 中末尾添加isolcpus=x
其中x为屏蔽的核心 X=3时为树莓派中的最后一个cpu(树莓派3b为例,cpu编号为0-3)
此处注意,添加的isolcpus=x不能起新行,需要写在原行的末尾,如:


dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=3a7978f6-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait isolcpus=3

添加后重启系统,使用htop命令查看cpu占用(没有可以用apt-get install htop安装),如下图:

树莓派提高实时性的几种方式(使用python测试)_第1张图片
htop命令下的cpu占用情况

此时系统自身调度不会再占用最后一个cpu(此处显示序号为4,因为是从1开始的,在系统中实际编号为3)

绑定cpu的方式:
python中,可以使用affinity库来绑定制定cpu(没有可以用pip install affinity 安装),affinity库一共提供了两个方法:

  • affinity.get_process_affinity_mask(pid)
  • affinity.set_process_affinity_mask(dwMask)

第一个方法传入pid,返回dwMask值,dwMask为CPU序号掩码,1(0001)代表只运行在CPU1,2(0010)代表只运行在CPU2,3(0011)代表可以运行在CPU1和CPU2,以此类推。
第二个方法传入dwMask, 返回0为成功,-1为失败.该方法需要root用户权限.
参考代码如下:

def run():
    while True:
        pass

p = multiprocessing.Process(target=run)
p.start()
pid = p.pid
print(affinity.get_process_affinity_mask(pid))
affinity.set_process_affinity_mask(pid, 15L)
print(affinity.get_process_affinity_mask(pid))

2.3 实时linux系统移植

出于通用性的考虑,本文只讨论linux系统的patch

2.3.1 RT-linux

Linux是典型的分时应用系统,对于实时性要求很高的应用,必须对内核本身动手术。而RTLinux则采取了一种比较聪明也比较折中的办法:他们实现一个最底层的精简的调度器,用于调度实时线程,原来的内核本身则成为实时调度器的一个优先级最低的任务。这样,当有实时任务时,普通内核已经建立于其上的普通进程被强制中断,实时线程被强制执行;只有当若有实时线程都让出cpu之后,普通内核才被运行,再由普通内核去调度执行普通的应用程序

移植方法:
(1)首先下载树莓派linux源代码:
git clone https://github.com/raspberrypi/linux.git

注意,由于该repo比较大,而git其实不支持断点续传(git init + git fetch + git checkout的方式实测并不能续传,每次断链再次fetch都是从头开始),所以建议只clone一个分支,且令depth为1,下载成功后再下载历史记录(如果需要),则命令改为:
git clone --depth=1 --single-branch --branch rpi-4.14.y git https://github.com/raspberrypi/linux.git

本文选用4.14,目前最新的树莓派内核版本为为4.14

(2)下载patch文件:
https://mirrors.edge.kernel.org/pub/linux/kernel/projects/rt/4.14/

patch压缩包,在本地解压出.patch文件,并移动到clone好的linux/文件夹下即可

(3)给linux内核打patch
进入clone好的linux文件夹,执行命令
cat *.patch | patch -p1

(4)下载编译
git clone https://github.com/raspberrypi/tools ~/tools

(5)配置PATH变量,注意32bit和64bit系统存在差异(如果是其他版本的树莓派则不是arm-bcm2708,1代为):
32位系统:

echo PATH=\$PATH:~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin >> ~/.bashrc
source ~/.bashrc

64位系统:

echo PATH=\$PATH:~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin >> ~/.bashrc
source ~/.bashrc
sudo apt-get install libc6:i386
sudo apt-get install lib32stdc++6
sudo apt-get install lib32z1

如果文件夹或路径不同注意自己改名,zsh同理
另外一些文章提到了另外一些依赖,如果可能也尽量安装(并不知道有何种影响,一般的报错可以先行google查询):

sudo apt-get install bc
sudo apt-get install libncurses5-dev libncursesw5-dev
sudo apt-get install zlib1g:i386
sudo apt-get install libc6-i386 lib32stdc++6 lib32gcc1 lib32ncurses5

(6)配置交叉编译设置
进入linux目录,修改Makefile文件
vim Makefile
找到如下语句
ARCH ?= arm,修改为 :
CROSS_COMPILE ?= /home/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
同样路径注意修改

(7)检查依赖
运行make menuconfig查看是否有报错,根据报错信息安装依赖或自行google

(8)进行编译

KERNEL=kernel7 
make bcm2709_defconfig
make zImage modules dtbs

如需多核加速编译可以加–j8参数等

(9)部署到内存卡
插入sd卡和读卡器(格式化,分区等参考fdisk等命令)
注意此sd卡已有rasbian系统
挂载:

mkdir mnt 
mkdir mnt/fat32 
mkdir mnt/ext4 
sudo mount /dev/sdb1 mnt/fat32 
sudo mount /dev/sdb2 mnt/ext4

安装:
sudo make INSTALL_MOD_PATH=mnt/ext4 modules_install

备份与拷贝内核:

sudo cp mnt/fat32/$KERNEL.img mnt/fat32/$KERNEL-backup.img 
sudo cp arch/arm/boot/zImage mnt/fat32/$KERNEL.img 
sudo cp arch/arm/boot/dts/*.dtb mnt/fat32/ 
sudo cp arch/arm/boot/dts/overlays/*.dtb* mnt/fat32/overlays/ 
sudo cp arch/arm/boot/dts/overlays/README mnt/fat32/overlays/ 
sudo umount mnt/fat32 
sudo umount mnt/ext4

(10)启动树莓派,检查是否安装成功
运行uname -a查看是否有RT字段

2.3.2 PREEMPT_RT

2.4 利用中断

2.5 连接外设(实时钟发生器)

2.6 超频

3. 测试

影响延迟的变量包括:

  • cpu是否满载(或其他cpu是否满载)
  • 是否使用python(考虑到解释器的延迟)

3.1 提高优先级

3.2 绑定cpu

3.3 实时操作系统移植

3.4 利用中断

4. 总结

后记

参考

  • 连接外设(MCU)
  • c语言测试
  • 交叉编译RT-linux
  • linux绑定单核的处理
  • RTLinux编程总结
  • 树莓派内核交叉编译与升级
  • PREEMPT_RT配置与内核编译
  • Linux RT(1)-硬实时Linux(RT-Preempt Patch)在PC上的编译、使用和测试

你可能感兴趣的:(树莓派提高实时性的几种方式(使用python测试))