Lua
进行脚本的开发,可是官方并没有提供很好的集成开发环境。体验了很多,发现
ZeroBrane Studio
这个开源软件还是非常好用的,并且已经能正常支持Linux
,Windows
,MacOS
这三个主流平台。
建议去官方网站下载最新的版本,但是鉴于国内网络访问不是非常稳定,可以从本站下载一份目前最新的版本。
下面的版本根据自身操作系统来选择其中一个进行下载
Lua
进行脚本的开发,可是官方并没有提供很好的集成开发环境。ZeroBrane Studio
这个开源软件还是非常好用的,并且已经能正常支持Linux
,Windows
,MacOS
这三个主流平台。
建议去官方网站下载最新的版本,但是鉴于国内网络访问不是非常稳定,可以从本站下载一份目前最新的版本。
下面的版本根据自身操作系统来选择其中一个进行下载
最新在使用的Raspberry Pi Zero W
V1.3
在使用目前(2018.09.26
)的系统的时候发现无法正常输出内容到屏幕上面,屏幕一直黑屏无信号。
原因在于Raspberry Pi Zero W
在启动的时候没有正确检测到屏幕信号,导致没有正常输出。
解决方法是打开启动配置文件/boot/config.txt
, 找到如下内容:
最近在使用树莓派与其他设备通过SPI
接口进行通信,使用一个GPIO
管脚触发读取数据的信号,为了简化开发,使用了Python
。
在实际运行过程中,发现当长时间运行的是,会出现中断管脚信号丢失的情况,在参考 Ubuntu 16.04 (x64)下从源代码为Raspberry Pi Zero W编译实时内核 更换为实时内核之后,短时间运行已经可以正常,但是在十几个小时之后,依然出现了中断丢失的现象。
这个现象初步评估为Python
的GC
动作时间过长导致的中断信号丢失。Python
本身并不是为实时系统设计的,因此在GC
进行垃圾回收的时候,是没有实时性的考虑的,因此在严格要求实时性的系统环境下,不是非常的合适。更何况很多的IO
操作默认都是阻塞的,更加容易导致实时性问题。
由于树莓派本身也是支持Lua
脚本的,默认安装的Lua
引擎默认是5.1.4
。Lua
本身在游戏中使用较多,而游戏本身对于实时性的要求是很高的。
尤其是Lua 5.1
开始使用最新的GC
已经能很好的解决实时性问题。
关于Lua
的GC
相关信息,参考如下的文章:
首先参考 Ubuntu 16.04 (x64)树莓派B+ (Raspberry Pi B+)源代码编译 保证能够成功编译标准内核的源代码,然后切换到实时内核分支,并执行如下编译命令:
Ubuntu
下面,SD
卡会自动挂载,默认挂载到了/media/
目录下面,如果是使用NOOBS
安装的话,系统目录是固定的,执行如下命令拷贝到目标SD
卡上面
有时,我们需要单独编译新下载的内核驱动,这个时候,就可以使用如下的方式进行单独内核模块的编译。
下面,我们以ASIX AX88772
系列的USB
有线网卡驱动的编译为例:
使用上面的命令安装完成内核后,目前(2018.09.26
)遇到的问题为,当插入ASIX AX88772
系列的USB
有线网卡之后,会导致内核崩溃,启动失败。
设备信息如下:
初步怀疑是USB
设备的驱动依赖关系不正确导致内核崩溃。
目前的临时解决方法为要求设备启动时候优先加载USB
设备相关的驱动,而不是等到网卡插入的时候再去加载。
也就是在/boot/config.txt
文件尾部新增加一行dtoverlay=dwc2
。这段代码本来是为树莓派通过USB
访问网络的虚拟网卡准备的(是的,你没看错,树莓派本身可以不借助网卡直接通过USB
接口跟电脑共享方式上网,不过需要设置一堆东西,最简单的还是外接真正的USB
网卡)。我们加载这个模块,但是并不使用这个功能,造成的结果就是重新调整了模块加载顺序,规避了后续的问题。
上述修改后,依旧存在动态插拔网卡,设备会重启的问题,不过已经不影响正常使用。
继续Python协程方面的介绍,这次要讲的是gevent,它是一个并发网络库。它的协程是基于greenlet的,并基于libev实现快速事件循环(Linux上是epoll,FreeBSD上是kqueue,Mac OS X上是select)。有了gevent,协程的使用将无比简单,你根本无须像greenlet一样显式的切换,每当一个协程阻塞时,程序将自动调度,gevent处理了所有的底层细节。让我们看个例子来感受下吧。
解释下,”gevent.spawn()”方法会创建一个新的greenlet协程对象,并运行它。”gevent.joinall()”方法会等待所有传入的greenlet协程运行结束后再退出,这个方法可以接受一个”timeout”参数来设置超时时间,单位是秒。运行上面的程序,执行顺序如下:
所以,程序运行下来的输出就是:
注意,这里与上一篇greenlet中第一个例子运行的结果不一样,greenlet一个协程运行完后,必须显式切换,不然会返回其父协程。而在gevent中,一个协程运行完后,它会自动调度那些未完成的协程。
我们换一个更有意义的例子:
我们通过协程分别获取三个网站的IP地址,由于打开远程地址会引起IO阻塞,所以gevent会自动调度不同的协程。另外,我们可以通过协程对象的”value”属性,来获取协程函数的返回值。
细心的朋友们在运行上面例子时会发现,其实程序运行的时间同不用协程是一样的,是三个网站打开时间的总和。可是理论上协程是非阻塞的,那运行时间应该等于最长的那个网站打开时间呀?其实这是因为Python标准库里的socket是阻塞式的,DNS解析无法并发,包括像urllib库也一样,所以这种情况下用协程完全没意义。那怎么办?
一种方法是使用gevent下的socket模块,我们可以通过”from gevent import socket”来导入。不过更常用的方法是使用猴子布丁(Monkey patching):
上述代码的第一行就是对socket标准库打上猴子补丁,此后socket标准库中的类和方法都会被替换成非阻塞式的,所有其他的代码都不用修改,这样协程的效率就真正体现出来了。Python中其它标准库也存在阻塞的情况,gevent提供了”monkey.patch_all()”方法将所有标准库都替换。
使用猴子补丁褒贬不一,但是官网上还是建议使用”patch_all()”,而且在程序的第一行就执行。
协程状态有已启动和已停止,分别可以用协程对象的”started”属性和”ready()”方法来判断。对于已停止的协程,可以用”successful()”方法来判断其是否成功运行且没抛异常。如果协程执行完有返回值,可以通过”value”属性来获取。另外,greenlet协程运行过程中发生的异常是不会被抛出到协程外的,因此需要用协程对象的”exception”属性来获取协程中的异常。下面的例子很好的演示了各种方法和属性的使用。
之前我们讲过在”gevent.joinall()”方法中可以传入timeout参数来设置超时,我们也可以在全局范围内设置超时时间:
上例中,我们将超时设为2秒,此后所有协程的运行,如果超过两秒就会抛出”Timeout”异常。我们也可以将超时设置在with语句内,这样该设置只在with语句块中有效:
此外,我们可以指定超时所抛出的异常,来替换默认的”Timeout”异常。比如下例中超时就会抛出我们自定义的”TooLong”异常。
greenlet协程间的异步通讯可以使用事件(Event)对象。该对象的”wait()”方法可以阻塞当前协程,而”set()”方法可以唤醒之前阻塞的协程。在下面的例子中,5个waiter协程都会等待事件evt,当setter协程在3秒后设置evt事件,所有的waiter协程即被唤醒。
除了Event事件外,gevent还提供了AsyncResult事件,它可以在唤醒时传递消息。让我们将上例中的setter和waiter作如下改动:
队列Queue的概念相信大家都知道,我们可以用它的put和get方法来存取队列中的元素。gevent的队列对象可以让greenlet协程之间安全的访问。运行下面的程序,你会看到3个消费者会分别消费队列中的产品,且消费过的产品不会被另一个消费者再取到:
put和get方法都是阻塞式的,它们都有非阻塞的版本:put_nowait和get_nowait。如果调用get方法时队列为空,则抛出”gevent.queue.Empty”异常。
信号量可以用来限制协程并发的个数。它有两个方法,acquire和release。顾名思义,acquire就是获取信号量,而release就是释放。当所有信号量都已被获取,那剩余的协程就只能等待任一协程释放信号量后才能得以运行:
上面的例子中,我们初始化了”BoundedSemaphore”信号量,并将其个数定为2。所以同一个时间,只能有两个worker协程被调度。程序运行后的结果如下:
如果信号量个数为1,那就等同于同步锁。
同线程类似,协程也有本地变量,也就是只在当前协程内可被访问的变量:
通过将变量存放在local对象中,即可将其的作用域限制在当前协程内,当其他协程要访问该变量时,就会抛出异常。不同协程间可以有重名的本地变量,而且互相不影响。因为协程本地变量的实现,就是将其存放在以的”greenlet.getcurrent()”的返回为键值的私有的命名空间内。
讲到这里,大家肯定很想看一个gevent的实际应用吧,这里有一个简单的聊天室程序,基于Flask实现,大家可以参考下。
RTL8192EU
(天猫魔盘)的无线网卡,使用如下方式安装驱动:需求:将形如’y\xcc\xa6\xbb’
的byte
字符串转化为integer
或者string
struct
包python3.2
及以上若byte
串采取大端法:
若采取小端法,则:
大端法:
小端法:
array
包其中I
用于表示大端或小端,且使用此方法要注意自己使用的python
版本。
如:
又如:
树莓派Zero
W
,有两款小型号,一款是Raspberry Pi Zero W
,另一款是Raspberry Pi Zero WH
,两者的区别是一个出厂的时候没有焊接排针,另一款焊接了排针。W
是Wireless
的缩写,WH
是Wireless With Head
的缩写。
树莓派Zero
W
/WH
(Raspberry Pi Zero W/WH
) GPIO
针脚定义如下图:
继续阅读树莓派Zero W/WH(Raspberry Pi Zero W/WH) GPIO针脚定义