使用 Python 对工业树莓派 I/O 进行远程控制

之前有一篇文章讲述了如何使用 Python 从虹科工业树莓派的过程映像文件中读写数据从而达到控制输入输出的谜底,可以使用三种方式:file 函数、ioctl 和 revpimodio2 库。其中以第三种方式最为简单方便。

首先让我们先回顾一下如何调用 revpimodio2 库,读写过程映像中的数据。

由上图可见,只需要先对 revpimodio 进行实例化,然后就可以直接通过变量名对数值进行操作了。这样一种方式确实十分方便,在可以满足大部分情况下的需求。但这种方式存在一个问题就是,python程序必须运行在本机上,且只能对本机的IO进行操作。但有时我们往往会遇到一些情况,需要对工业树莓派进行远程控制,甚至多个工业树莓派之间协同工作,互相调取过程数据。那遇到这种情况我们又该如何应对呢?

幸运的是 revpimodio2 库文件不仅仅包含了上面一种操作方式,还提供一种称为 RevPiNetIO 的调用方式。运行在其它机器上的 python 程序可以通过工业树莓派的IP地址建立远程连接,从而实现远程控制。但这种方式需要工业树莓派 RevPiPyLoad 的支持, RevPiPyLoad 将作为 RevPiNetIO 的服务器,提供通过网络读写过程映像数据的能力。

1.启用 RevPiPyLoad

RevPiPyLoad已预装载在虹科工业树莓派内,在正式开始之前我们首先需要启用这个功能。

# start daemon sudo service revpipyload start # stop daemon sudo service revpipyload stop # reload settings sudo service revpipyload reload # restart daemon sudo service revpipyload restart

可通过sudo service revpipyload status命令查看服务运行状态,如出现无法连接情况,可尝试重启设备。

2.更改配置文件

更改以下配置文件,启用 plcslave 选项。

sudo nano /etc/revpipyload/revpipyload.conf

Ctrl+X保存并退出。然后修改以下文件:

sudo nano /etc/revpipyload/aclplcslave.conf

向最后一行添加*.*.*.*,1,修改这个文件的作用是控制访问权限,允许文件中所添加的IP对应的主机进行远程控制访问。本例中允许所有主机进行访问控制。最后的“1”代表读写权限,“1”是可读可写。

3.尝试建立连接

工业树莓派已准备就绪,下面尝试使用远程主机建立连接。在本例中使用windows10系统的远程主机。过程如下:

3.1 安装 revpimodio2

Windows电脑已安装Python3运行环境,如未安装,请先安装Python。

首先win+R打开“运行”,输入“cmd”并确认,从而打开命令提示符窗口。运行以下命令:

pip3 install revpimodio2

安装完成之后python程序就可以调用revpimodio2库了。

3.2 一段简单的测试代码

在 windows 电脑上新建 test.py 文件,输入以下代码,并运行。

上图中IP地址为树莓派的IP。此段代码的作用就是每隔1s改变数字输出通道1的输出状态。本例采用的是 RevPi Compact,运行效果如下所示:

至此我们已经成功通过远程主机对工业树莓派进行远程控制。如未成功,请检查前面的配置或尝试重启设备。

3.3 更进一步

下面我们尝试一个稍微复杂的程序,做一个类似流水灯一样的效果。

新建 LightSwitch.py 文件,并输入以下代码,并运行 :

运行效果如下:

4.总结

虽然本例实现的程序和效果都比较简单,但借助这个功能,开发者可以实现很多功能。最基本的就是对虹科工业树莓派进行远程控制。另外也可以通过创建多个RevPiNetIO实例,实现多个工业树莓派系统协同工作。

另外本文中使用的 RevPiPyLoad 的功能也不仅仅如此,它还可以作为图形配置工具 RevPiControl 的 server,或者通过MQTT协议将IO的数值发布出去。

关于 revpimodio2 和 RevPiPyLoad 的更多功能,可以参考以下网址:https://revpimodio.org/en/homepage/

树莓派 Pico + LCD1602 显示个性化字符

让 LCD 显示屏显示个性化的字符,有点类似于创作一套 emoji 那样有趣。下面我们介绍实现的方法。

用到的东西

– 树莓派 Pico

– LCD1602 显示屏(带 I2C 模块)

– 面包板

– 跳线若干

接线

如图所示接线。

SCL-Pin 2 (GP1)

SDA-Pin 1(GPO)

VCC-Pin 40(VBUS)

GND-Pin 38 (GND)

编程

接线完成下面开始编程。

首先确保你的 Pico 已经安装了 MicroPython 固件。

1、下载 Thonny 编程工具。

2、打开 Thonny 在 Tools> Options> Interpreter 选择 Raspberry Pi Pico 为解释器。

下载 LCD1602 的驱动和库。

https://github.com/T-622/RPI-PICO-I2C-LCD

运行代码之前,需要确认 LCD 1602 的 I2C 地址。下载下面的代码确认 I2C 地址:

https://github.com/gigafide/pico_LCD_16x2

保存为文件之后运行,电脑上会显示一个十进制的数字。需要再通过十进制转十六进制的工具将数字转换成 I2C 地址。

实现个性化字符

使用下面的代码可以显示字符。

import machine from machine import I2C from lcd_api import LcdApi from pico_i2c_lcd import I2cLcd I2C_ADDR = 0x27 I2C_NUM_ROWS = 4 I2C_NUM_COLS = 20 i2c = I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000) lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS) lcd.clear(_) lcd.move_to(0,5) lcd.putstr(“Hello”) lcd.move_to(0,5) lcd.putstr(“World!”)

你只需要修改最后四行,就可以让它显示个性化字符。个性化字符的代码可以通过这个工具创建。然后用 Python 的方法定义即可。

# smiley faces happy = bytearray([0x00,0x0A,0x00,0x04,0x00,0x11,0x0E,0x00]) sad = bytearray([0x00,0x0A,0x00,0x04,0x00,0x0E,0x11,0x00]) grin = bytearray([0x00,0x00,0x0A,0x00,0x1F,0x11,0x0E,0x00]) shock = bytearray([0x0A,0x00,0x04,0x00,0x0E,0x11,0x11,0x0E]) meh = bytearray([0x00,0x0A,0x00,0x04,0x00,0x1F,0x00,0x00]) angry = bytearray([0x11,0x0A,0x11,0x04,0x00,0x0E,0x11,0x00]) tongue = bytearray([0x00,0x0A,0x00,0x04,0x00,0x1F,0x05,0x02]) # icons bell = bytearray([0x04,0x0e,0x0e,0x0e,0x1f,0x00,0x04,0x00]) note = bytearray([0x02,0x03,0x02,0x0e,0x1e,0x0c,0x00,0x00]) clock = bytearray([0x00,0x0e,0x15,0x17,0x11,0x0e,0x00,0x00]) heart = bytearray([0x00,0x0a,0x1f,0x1f,0x0e,0x04,0x00,0x00]) duck = bytearray([0x00,0x0c,0x1d,0x0f,0x0f,0x06,0x00,0x00]) check = bytearray([0x00,0x01,0x03,0x16,0x1c,0x08,0x00,0x00]) cross = bytearray([0x00,0x1b,0x0e,0x04,0x0e,0x1b,0x00,0x00]) retarrow = bytearray([0x01,0x01,0x05,0x09,0x1f,0x08,0x04,0x00]) # battery icons battery0 = bytearray([0x0E,0x1B,0x11,0x11,0x11,0x11,0x11,0x1F])) # 0% Empty battery1 = bytearray([0x0E,0x1B,0x11,0x11,0x11,0x11,0x1F,0x1F])) # 16% battery2 = bytearray([0x0E,0x1B,0x11,0x11,0x11,0x1F,0x1F,0x1F])) # 33% battery3 = bytearray([0x0E,0x1B,0x11,0x11,0x1F,0x1F,0x1F,0x1F])) # 50% battery4 = bytearray([0x0E,0x1B,0x11,0x1F,0x1F,0x1F,0x1F,0x1F])) # 66% battery5 = bytearray([0x0E,0x1B,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F])) # 83% battery6 = bytearray([0x0E,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F])) # 100% Full battery7 = bytearray([0x0E,0x1F,0x1B,0x1B,0x1B,0x1F,0x1B,0x1F])) # ! Error lcd.custom_char(0, happy); lcd.putchar(chr(0)) #lcd.putchar(b’\x00′)

https://maxpromer.github.io/LCD-Character-Creator/

via

一份全面的树莓派 Pico 入门指南

2021年1月底的时候,树莓派基金会发布了一个重磅消息,推出了进军微控制器领域的树莓派Pico。

功能强劲,价格便宜的特性让Pico受到了全世界创客们的关注,这篇文章就来给大家介绍一下Pico这个小玩意儿。

文章原文来自DroneBot Workshop,负责人是一个非常和蔼的老爷爷。有条件的小伙伴可以去油管关注一下他。

这篇文章使用MicroPython在树莓派 Pico上编程,一起来看看三十块的微控制器究竟能做些什么。

https://www.bilibili.com/video/BV1tr4y1N7pv

介绍

树莓派基金会发布微控制器本身就是一个大消息,毕竟在这之前,这个世界上最流行的单板电脑的制造商从来没有表示过对微控制器的兴趣。

不仅仅是树莓派Pico的公布让人感到意外,这次树莓派还自己打造了一款新的芯片。他们没有在现有代码的基础上,支持基于ESP32或SAMD21的设计,而是选择创建自己的微控制器。

所以谈到Pico时,我们都是新手。

树莓派也在官网发布了一大堆技术文档,还有一本名为《Get Started with MicroPython on Raspberry Pi Pico》的说明书。它有纸质版,也有PDF版下载。

除此之外,目前还没有关于Pico更深入的资料。不过随着时间的推移,这种情况很快就会改变,树莓派已经授权包括Adafruit在内的其他厂商在自己的设计中使用RP2040芯片。假以时日,就会给我们带来更多的代码和开发工具。

我们先来尝试一下,给Pico连接上一堆东西,会发生什么有趣的事情吧!

树莓派 Pico

Pico是一块小小的板子,大小和Arduino Nano差不多。和所有树莓派一样,包装非常简陋,只是一个塑料包装内的Pico,而塑料包装本身就是从一条条的包装上剪下来的,非常像小时候吃的咪咪虾条或者是糖果的包装。

看看Pico的板子

四刀买到的就仅仅是这么一款裸板,没有多的,就是这么环保。

裸板不带针脚,需要自己焊。这是一块做工精良的电路板,也可以作为SMD元件,直接焊接到印刷电路板上。

俯视图

从顶部看,Pico是这样的。

板上最主要的功能是一端的microUSB连接器。它既用于通信,也用于给Pico供电。

在microUSB连接器旁边安装了一个板载LED,它内部连接到GPIO针脚25。

值得注意的是,这是整个Pico板上唯一的LED。

开机按钮安装在离LED稍低一点的地方,它可以让你改变Pico的启动模式,这样你就可以在上面加载MicroPython,进行拖拽式编程。

在板子的底部,你会看到三个连接点,这些连接点是用于串行Debug选项的,我们今天是入门,暂时不探讨这个问题,高级开发者会比较感兴趣。

在板子的中央是整个板子的“大脑”——RP2040 MCU,我们一会儿就会研究它的功能。

接地引脚

板子上有好几个地线,8个地线加上3针Debug连接器上的一个附加地线。

这些引脚很容易发现,它们是均匀的,而且是方形的,而不是像其他连接的圆形。

其中一个位于33号针脚的地线也被指定为模拟地线。

电源引脚

Pico是一个3.3V的逻辑器件,但由于内置了电压转换器和稳压器,它可以用一系列电源供电。

所有与电源相关的引脚都被安排在了一起,靠近microUSB连接器。

– VBUS – 这是来自 microUSB 总线的电源,5 V。如果Pico不是由microUSB连接器供电,那么这里将没有输出。

– VSYS – 这是输入电压,范围为 2 至 5 V。板载电压转换器将为 Pico 将其改为 3.3 V。

– 3V3 – 这是 Pico 内部调节器的 3.3 伏输出。只要将负载保持在 300ma 以下,它就可用于为其他组件供电。

还有几个输入可以让你控制 Pico 的电源。

– 3V3_EN – 你可以使用此输入禁用 Pico 的内部电压调节器,从而关闭 Pico 和由其供电的任何组件。

– RUN – 可以启用或禁用 RP2040 微控制器,也可以将其复位。

GPIO 引脚

树莓派 Pico板上有26个裸露的GPIO连接。

它们的排列顺序很好,在GPIO 22和GPIO 26之间有一个 “空隙”(这些 “缺失 “的引脚在内部使用)。

这些引脚都有多种功能,你可以为PWM配置多达16个引脚。

有两个I2C总线,两个UART和两个SPI总线,这些可以配置使用多种GPIO引脚。

模拟引脚

Pico有三个模数转换器,还有一个内部用于板载温度传感器的转换器。

ADC的分辨率为12位。

你也可以在ADC_VREF引脚上提供一个外部精密电压参考。其中一个接地点,即33脚上的ADC_GND被用作该参考点的接地点。

RP2040微控制器

树莓派 Pico是围绕基金会的新芯片RP2040微控制器而设计的。下面是它的参数:

– 双核32位ARM Cortex -M0+处理器

– 运行在48MHz,但可以超频到133MHz。

– 30个GPIO引脚(26个暴露)

– 可支持USB主机或设备模式

– 8 可编程I/O(PIO)状态机

RP2040能够支持高达16MB的片外闪存,不过在Pico中只有4MB。

树莓派基金会对这款芯片有很多计划,也已经授权给了很多其他厂商。

对Pico进行编程

你可以使用两种编程语言之一开始使用 Pico。

MicroPython – 一种专门为微控制器制作的解释语言。

C++ – 许多微控制器用户都熟悉C++,因为它被用于Arduino和ESP32板上。

虽然我急于将C++与Pico一起使用,以榨取它的每一克性能,但还是决定与大多数人一样,使用MicroPython。在这个早期的开发阶段,C++的工具还在进行最后的开发,期待着Pico成为PlatformIO和Arduino IDE板系列的一部分。

开始使用Pico

当我们拿到Pico板时,它被包装在一个塑料载体中,没有额外的零件。

除非你有计划将 Pico 表面贴装,或者你的唯一目的是只是点个灯,否则我们都需要一些引脚。

Pico 有 40 个引脚,每侧 20 个。另外三个针脚用于调试端口。

标准的公头针脚有 40 个针脚带,因此可以将其中一个针脚带减半,作为 Pico 的针脚使用。如果你想在 Debug 连接器上安装针脚,你需要另一个 3 针的公头,可以是直的或 90 度的。

焊接一个Pico

在开始对 Pico 进行编程之前,我们需要进行一些焊接工作!除了杜邦公头引脚之外,我们还需要合适的烙铁和一些焊料。

电烙铁的头需要精细一点,我们还需要一块清洁海绵和一个支架。

此外,我们还需要想办法在焊接Pico引脚时把它固定住,因为它们需要以精确的90度角安装到电路板上,这样才能装入无焊料面包板。

许多实验都使用无焊面包板来固定引脚,虽然这种方法可行,但有可能因热力或焊料飞溅而损坏面包板。

所以最好的解决方法是,你有一块老旧的面包板,用它作为针座。

我个人喜欢用几块便宜的灌注板、打孔实验板。我说的 “便宜 “是指单面的东西,没有排孔,只有一面是裸铜的。

两片这种东西很适合固定引脚,每当要焊接一个小模块或者单片机的时候,我就经常用这个。

把电烙铁加热到一定温度,然后加热引脚与焊盘的连接处,在另一面涂上焊料,千万不要直接涂到电烙铁上。加热零件,而不是焊料。

如果你想焊接Debug的3个引脚连接器(这是可选的),你可能应该先做。这些引脚的方向与GPIO引脚的方向相反。我用了一个小的便签垫来固定电路板,因为Debug连接器与GPIO引脚在网格上并不一致。

之后就是焊接40个引脚了,一次20个! 真的不需要太长的时间,只需要用尽可能多的焊料,避免出现焊桥,完成后再检查一下。

焊接后清理Pico

我喜欢在焊接完我的PCB后清洗它们,以去除焊料核心中的助焊剂和树脂。它表现为焊接连接处周围的褐色污渍。

这一步完全是可有可无的,因为助焊剂和树脂对元件的运行或寿命没有任何不利影响。它只是看起来更好看!

如果你想克隆你的板子,你需要一些PCB板清洗剂或Flus Remover。由于它也往往会留下一点残留物,我用异丙醇来清理。

PCB板清洗剂可以到网上购买。异丙醇可以在当地药店找到,一定要买纯酒精和水的混合物(70%),不要买有香味的。

我用一把旧牙刷和一些塑料容器,在一个盆子里进行工作。记得最好要准备好口罩、手套和护目镜。

我用牙刷蘸PCB清洁剂擦洗引脚,然后用牙刷蘸异丙醇冲洗。

让板子自然风干,也可以使用空气软管,这样之后,我们将拥有一个闪闪发光的新Pico!

Pico 和 Thonny IDE

现在Pico的引脚已经连接好了,我们可以开始对它进行实验了。

建议你把它放在一个无焊的面包板上,以迎接我们即将到来的实验。

虽然有许多IDE可以让我们选择与我们的新Pico一起工作,但我的建议是使用树莓派推荐的Thonny IDE。

Thonny IDE

Thonny自称是 “Python IDE for Beginners”,它适用于Windows、Mac OSX和Linux。

它也是树莓派操作系统(以前的Raspbian)的一部分。

我将在树莓派操作系统上使用Thonny IDE,运行在8GB的树莓派 4上,作为我今天实验的开发平台。当然,你可以使用任何你能运行Thonny的平台,但我想让它在树莓派家族中运行–另外,由于Thonny已经安装在新构建的树莓派操作系统上,所以上手非常简单。

启动和安装MicroPython

我们需要做的第一件事是将MicroPython安装到Pico上。

将microUSB连接到Pico上,并准备将另一端插入电脑。在插入之前,先按下Pico上的Boot Select(开关)按钮。

按住BOOTSEL键,将Pico插入电脑的USB端口。按住BOOTSEL键几秒钟,然后松开。

你应该会看到一个新的驱动器在你的电脑上可用,信息看起来会有所不同,这取决于你所使用的操作系统,但它类似于你将U盘插入电脑时得到的信息。

打开新的 “驱动器”,你会看到一个名为 RPI-RP2的文件夹。在这个驱动器里,你会看到几个文件,其中一个是网页文档index.htm。

点击该网页文件,浏览器就会打开,你会被重定向到树莓派 Pico入门页面。

点击MicroPython入门的标签。你会看到一个链接来下载一个UF2文件,这就是可下载的MicroPython文件。把这个文件下载到你的电脑上。

现在将下载的文件拖到Pico的RPI-RP2文件夹中。一旦这样做了,文件夹就会消失,Pico将以MicroPython模式启动。

配置 Thonny IDE

在Pico仍然被连接的情况下,打开Thonny IDE,如果你和我一样使用树莓派操作系统,你会在编程工具菜单下找到Thonny。

一旦Thonny打开,请看右下角的状态栏,它可能会显示一个Python的版本。这是当前在你的计算机上运行的Python版本,对于我们的实验来说,这一点并不重要。

点击该消息,应该会出现一个下拉菜单,还有其他环境可以选择。其中一个应该是MicroPython (树莓派 Pico)。选择那一个。

你会注意到底部打开了一个新的Shell,在这个Shell中,你应该会看到一些文字,表明你已经连接到Pico。

是时候开始编程了!

Shell 测试

Shell是Pico的 “命令行”,你可以直接在这里执行代码。

一个简单的测试是输入以下内容(这也是查看你是否正确连接到 Pico 的好方法),然后按 Enter 键。

print(“Hello World”)

你应该在shell中看到 “Hello World “被打印出来了,当然这是你告诉Pico要做的。

脚本测试

当然,你不会直接在shell中输入你的程序,一来,一旦你执行了程序,它们就会消失,二来,对于任何相当大的程序来说,也是不方便的。

你要用编辑器来输入你的程序,也就是shell上面的大文本区域,在Thonny IDE的屏幕上占主导地位。

进入这个编辑器,输入和刚才一样的文字,用一个漂亮的 “你好 “来迎接编程世界。

点击 “运行 “按钮(绿色带箭头的那个),系统会提示你先保存程序。你可以选择将其保存在本地电脑或Pico上,尝试保存在Pico上。给你的程序起个带”.py “后缀的名字,比如 “hello.py”。

程序将被保存并运行,你将在shell中看到 “Hello World “的问候语。你可以按 “运行 “按钮再次看到它,再按一次。

所以,现在你知道了如何编写和保存MicroPython程序,我们就可以开始我们的实验了!

使用LED和开关

基本的数字I/O功能可以很容易地用LED和开关来说明,这正是我们开始Pico冒险的方式。

但请注意我们如何给开关布线,我们将以不同的方式进行操作。

RGB LED

最简单的输出设备可能是LED。当在正确的方向上施加足够的电流时,这种输出设备就会工作。虽然简单,但它可以用来说明I/O技术,这些技术可以应用于其他设备,如继电器或晶体管。

我将使用一个Common-Cathode RGB LED,但你也可以使用三个分立的LED来代替。无论哪种方式,你都还需要三个降压电阻,我在实验中使用了330欧姆的电阻。

如果你选择像我这样使用RGB LED,一定要买一个标准的RGB LED,而不是一个可编程的。

按钮开关

这是最简单的输入设备。我用的是一对瞬时常开按钮开关

一个红色和一个黑色,但在其他方面是相同的。

我们再次使用一个简单的输入设备来测试我们的小Pico的I/O能力。我们将以不同的方式为两个开关布线,使其更加有趣,而且我们也不会使用任何上拉或下拉电阻。

LED和开关的连接

这里是我们的LED和开关的连接图,请记住,如果你没有共阴极RGB LED,你可以使用三个独立的LED。

请注意,这两个开关的接线方式不同。

黑色按钮开关的一侧连接到Pico的GPIO引脚,另一侧连接到地。

红色开关则相反,它的一侧连接到GPIO引脚,另一侧连接到3.3伏,这是Pico的工作电压和逻辑电压。

经典项目——点灯

我们要做的第一个实验是我们自己的Arduino “Blink “草图的变体。是的,从技术上讲,我们已经看到了如何闪烁板载LED,但由于我们现在有一个RGB LED在我们的支配下,我们当然可以找到另一种方法来点灯!

在Thonny中打开以下代码。

# 树莓派 Pico RGB Blink # rgb-blink.py # RED LED – Pico GPIO 10 – Pin 14 # GREEN LED – Pico GPIO 11 – Pin 15 # BLUE LED – Pico GPIO 14 – Pin 19 # DroneBot Workshop 2021 # https://dronebotworkshop.com import machine import utime led_red = machine.Pin(10, machine.Pin.OUT) led_green = machine.Pin(11, machine.Pin.OUT) led_blue = machine.Pin(14, machine.Pin.OUT) while True: led_red.value(1) led_green.value(0) led_blue.value(0) utime.sleep(2) led_red.value(0) led_green.value(1) led_blue.value(0) utime.sleep(2) led_red.value(0) led_green.value(0) led_blue.value(1) utime.sleep(2) led_red.value(1) led_green.value(1) led_blue.value(0) utime.sleep(2) led_red.value(1) led_green.value(0) led_blue.value(1) utime.sleep(2) led_red.value(0) led_green.value(1) led_blue.value(1) utime.sleep(3) led_red.value(1) led_green.value(1) led_blue.value(1) utime.sleep(2) print(“End of Loop”) led_red.value(0) led_green.value(0) led_blue.value(0) utime.sleep(2)

这是一个简单的脚本,肯定可以改进,但它可以很好地说明我们的观点。

我们先导入 machine 和 utime 库。你会发现,任何涉及I/O端口的活动都需要用到machine,而只要我们想使用时间函数,就需要用到utime。

然后,我们定义三个 LED 元件的连接,请注意,它们是以 GPIO 编号而非 Pico 上的物理引脚编号来表示的。我们将所有这些引脚定义为 machinePin.OUT,这意味着这些引脚现在被设置为输出引脚。

while True条件类似于Arduino草图中的Loop,这里的代码是连续执行的。

在本节中,我们对LED进行寻址,并将它们设置为开(值为1)或关(值为0)。我们通过一个序列,在最后一个序列,我们打印到控制台。

然后我们再做一遍。

将脚本加载到Pico上,然后观察LED,你应该会看到一个彩色的闪烁。

开关测试

我们接下来的脚本是对两个开关进行一个非常基本的测试,我们用这样一个奇怪的方式来接线。

你会观察到的第一件奇怪的事情是它们的接线不同,黑色的开关将输入端连接到地,而红色的开关将输入端连接到3.3伏,用于逻辑HIGH。

另一个有趣的事情是,这两个开关都没有采用上拉或下拉电阻,它们显然需要这些电阻,黑色开关需要上拉,红色开关需要下拉才能正常工作。

我们将在代码中加入所需的电阻!

# 树莓派 Pico Switch Test # switchtest.py # RED BUTTON – Pico GPIO 15 – Pin 20 # BLACK BUTTON – Pico GPIO 2 – Pin 4 # DroneBot Workshop 2021 # https://dronebotworkshop.com import machine import utime button_red = machine.Pin(15, machine.Pin.IN, machine.Pin.PULL_DOWN) button_black = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP) while True: if button_red.value() == 1: print(“Red”) if button_black.value() == 0: print(“Black”) utime.sleep(0.25)

请注意定义按钮的行的语法,你会看到它们是如何被定义为Inputs的,以及如何添加了下拉和上拉电阻。

在while True: 循环中,你还会注意到我们是在监测不同的条件,红色的开关触发了一个HIGH输入,而黑色的开关触发了一个LOW。

最后的微小时间延迟是一种简单的debouncing形式,如果你喜欢,你可以实验一下这个值。

这个脚本会在控制台中打印所有的结果,所以在你按下按钮的时候要注意。

中断和切换

接下来的实验引入了几个有用的概念。第一个,也可以说是这两个概念中最重要的,就是 “中断”。

中断

中断就像它的声音一样,是一个 “中断 “程序正常流程的事件。在我们的情况下,我们处理的是外部硬件中断,这意味着在程序继续运行之前,需要处理一个信号或状态变化。

在Pico上,我们按照以下方式创建一个中断。

我们将一个引脚定义为 “中断输入”, 我们定义该点上的状态变化被认为是一个中断。在 Pico 上,我们可以使用任何 GPIO 引脚来实现这一点,而且我们可以定义多个引脚。

我们创建了一个 “中断处理程序 “函数,我们希望在检测到中断时运行该函数。

我们将 “中断处理程序 “与 “中断输入 “配对。

现在,每当中断输入条件发生时,Pico 将停止它正在做的任何事情,并执行 “中断处理程序”。然后它将恢复到原来的位置。

切换

虽然不像中断那样基本,但仍然非常有用。“切换”只是将 Pico 上的输出状态反转。

因此,如果输出为高电平,而我们应用 “切换”,它就会变为低电平。

我们不需要知道输出的当前状态,我们只需要知道当我们应用一个切换器时,它将变为相反的状态。

自然,这是写另一个Blink程序的理想函数,所以我们会这么做。只有我们的Blink程序才会有被中断的风险!

# 树莓派 Pico Interrupt & Toggle Demo # interrrupt-toggle-demo.py # RED LED – Pico GPIO 10 – Pin 14 # GREEN LED – Pico GPIO 11 – Pin 15 # RED BUTTON – Pico GPIO 15 – Pin 20 # DroneBot Workshop 2021 # https://dronebotworkshop.com import machine import utime led_red = machine.Pin(10, machine.Pin.OUT) led_green = machine.Pin(11, machine.Pin.OUT) led_red.value(0) led_green.value(0) button_red = machine.Pin(15, machine.Pin.IN, machine.Pin.PULL_DOWN) def int_handler(pin): button_red.irq(handler=None) print(“Interrupt Detected!”) led_red.value(1) led_green.value(0) utime.sleep(4) led_red.value(0) button_red.irq(handler=int_handler) button_red.irq(trigger=machine.Pin.IRQ_RISING, handler=int_handler) while True: led_green.toggle() utime.sleep(2)

在这个MicroPython脚本中,我们将闪烁我们的RGB LED的绿色部分,使用一个切换器来改变它的状态。在正常的操作下,LED状态将每两秒钟切换一次。

然而,我们可以通过按下红色按钮来中断闪烁。这将导致一个中断,这将关闭绿色的LED,然后打开红色的。它将保持四秒,之后程序控制权将被恢复,因此我们可以继续进行绿色闪烁。

我们通过导入machine和utime库来开始我们的脚本,就像我们之前一样。

LED段和红色按钮的定义和之前的脚本一样。LED在程序启动时被关闭。

然后我们定义一个函数,这是我们的中断处理程序,叫做 “int_handler”。在这个函数中,我们做了以下工作。

– 关闭中断,这样我们就不会有多个中断了。

– 将 “中断检测 “打印到Shell上

– 打开红色LED段。

– 关闭绿色LED段。

– 睡眠四秒。

– 关闭红色段。

– 重新建立中断

– 退出

处理函数后的那一行将中断 “粘 “到我们定义为红色按钮输入的引脚上。需要注意的是,它指定了 “IRQ_RISING”,这意味着如果输入从0(地)上升到1(3.3伏),它将触发一个中断。这与我们红色按钮的接线方式一致。

在True循环中,我们只需使用定义为输出的任何GPIO引脚可用的 “toggle “功能来闪烁LED。

将它发送到Pico上,观察RGB LED,它应该开始闪烁绿色。观察一段时间,然后按下红色按钮。LED应该变成红色,Shell应该显示 “Interrupt Detected”。四秒钟后,绿色闪烁将重新开始。

开关和LED演示

既然我们一直在研究开关和LED,我们不妨把它们结合起来,再编写一个简单的脚本。

# 树莓派 Pico Switch & RGB LED Demo # switch-led-demo.py # RED LED – Pico GPIO 10 – Pin 14 # GREEN LED – Pico GPIO 11 – Pin 15 # BLUE LED – Pico GPIO 14 – Pin 19 # BLACK BUTTON – Pico GPIO 2 – Pin 4 # DroneBot Workshop 2021 # https://dronebotworkshop.com import machine import utime led_red = machine.Pin(10, machine.Pin.OUT) led_green = machine.Pin(11, machine.Pin.OUT) led_blue = machine.Pin(14, machine.Pin.OUT) led_red.value(0) led_green.value(0) led_blue.value(0) button_black = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP) while True: if button_black.value() == 0: led_red.value(1) led_green.value(0) led_blue.value(0) utime.sleep(1) led_red.value(0) led_green.value(1) led_blue.value(0) utime.sleep(1) led_red.value(0) led_green.value(0) led_blue.value(1) utime.sleep(1) led_red.value(0) led_green.value(0) led_blue.value(0)

这个很简单,现在大家应该对它的操作很熟悉了。我们用machine库函数定义RGB LED和黑色按钮。

记住,黑色按钮是由我们定义的上拉保持HIGH的,当按钮被按下时,它就会变LOW,因为另一边是接地线的。

所以在True循环中,我们寻找一个 “0 “的值,以表示按钮被按下。一旦我们检测到这个条件,我们就会通过它们的颜色循环LED段。

正如我所说,很简单的东西。

模拟输入测试

现在我们来谈谈模拟输入。

树莓派 Pico有三个模拟输入,它们都有12位的分辨率。

这三个输入端如下。

– GPIO 26 – ADC0 (31针)

– GPIO 27 – ADC1 (针脚 32)

– GPIO 28 – ADC2 (针脚34)

还有第四个ADC用于内部温度传感器。

电位计的连接

在我们的测试中,我们将使用一个电位器在模拟输入端呈现一个可变电压,然后我们将读取该电压。我们将使用ADC0作为我们的电位计输入,但你也可以使用其他两个中的一个。

请注意,虽然我将23号针脚显示为地线,这只是为了方便,但你可以使用任何Pico地线针脚。在33号针脚处还有一个特殊的模拟地,你可以使用。在我的面包板上,我将33号针脚与其他一些地线相连。

电位计读数

我们要做的第一个实验是简单地读取我们在模拟输入端得到的值,这个值应该根据我们电位器的位置而波动。

# 树莓派 Pico Analog Input Test # analog-input.py # POT – Pico GPIO 26 ADC0 – Pin 32 # DroneBot Workshop 2021 # https://dronebotworkshop.com import machine import utime potentiometer = machine.ADC(26) while True: print(potentiometer.read_u16()) utime.sleep(2)

这是一个简单的脚本,像往常一样,首先导入用于GPIO操作的machine库和用于时间函数的utime库。

然后我们定义我们的电位器连接。请注意我们如何使用 “ADC “来表示我们要将GPIO 26针作为模拟输入。当然这只适用于具有模拟输入能力的三个GPIO引脚。

在True循环中,我们只需打印从电位器上得到的值,然后延迟几秒钟再做一次。

需要注意的是,我们用 “read_u16 “函数得到的值的类型是一个无符号的16位整数。这意味着它将在0和65,535之间变化,而不是你可能期望从12位ADC中得到的4095。

这可能看起来很奇怪,但正如我们将在下一个脚本中看到的那样,能够传递具有相同数值数据类型的值实际上是有用的。

运行脚本并观察Shell,你应该会看到那里的数值随着你移动电位器轴而改变。

LED PWM 控制

让我们在之前的脚本基础上进行扩展,使用电位器的输出来控制LED的亮度。

当然,我们将使用PWM进行控制,这个任务在MicroPython中非常简单。

# 树莓派 Pico LED PWM Test # led-pwm.py # POT – Pico GPIO 26 ADC0 – Pin 32 # RED LED – Pico GPIO 10 – Pin 14 # DroneBot Workshop 2021 # https://dronebotworkshop.com import machine import utime led_red = machine.PWM(machine.Pin(10)) potentiometer = machine.ADC(26) led_red.freq(1000) while True: led_red.duty_u16(potentiometer.read_u16())

在这个脚本中需要注意的一个关键项目是我们定义 “led_red “的方式。我们将其定义为 “PWM”,而不是输出。

电位器的定义与上一个脚本中的方式完全相同。

现在我们已经给输出赋予了 “PWM “的属性,它继承了许多其他参数。其中之一是PWM频率,我们将其设置为1000 Hz。

在true循环中,我们不断地从电位器中获取无符号的16位值,并将其传递给LEDs占空比,也方便地指定为无符号的16位整数。

这就说明了两者保持相同的编号方案的价值,不需要将模拟值,真的是0到4095,映射到占空比,真的是0到100。

运行程序,你应该可以顺利地控制红色LED段的亮度。

添加显示屏

我们将进行的下一个实验是将一个OLED显示器连接到我们的Pico上,当然,也可以在上面打印一些东西。

我们将使用 I2C 显示屏,因此我们也将看到 Pico 如何使用 I2C 连接工作。记住,Pico有两条I2C总线。

我们的OLED是标准的1602型OLED显示器,到处都有。如果你愿意,也可以使用与我的显示屏尺寸不同的显示屏,只需在代码中更改尺寸即可。

这是我们如何把这些东西都挂起来的,只有四根线。

我们的显示器需要一个库,我们可以使用Thonny ID安装。你可能会发现在全菜单模式下比在基本模式下更容易,但这两种方式都可以。

– 点击 “工具 “菜单

– 点击 “管理包”

– 搜索 “ssd1306”

– 找到 “ssd1306.py “并安装它。

现在我们已经安装了库,我们可以看一下演示OLED显示屏的脚本。

# 树莓派 Pico OLED Display Test # Uses ssd1306 module # display-ssd1306-test.py # DroneBot Workshop 2021 # https://dronebotworkshop.com import machine import utime sda=machine.Pin(20) scl=machine.Pin(21) i2c=machine.I2C(0, sda=sda, scl=scl, freq=400000) from ssd1306 import SSD1306_I2C oled = SSD1306_I2C(128, 32, i2c) print(i2c.scan()) oled.text(‘Welcome to the’, 0, 0) oled.text(‘Pi Pico’, 0, 10) oled.text(‘Display Demo’, 0, 20) oled.show() utime.sleep(4) oled.fill(1) oled.show() utime.sleep(2) oled.fill(0) oled.show() while True: oled.text(“Hello World”,0,0) for i in range (0, 164): oled.scroll(1,0) oled.show() utime.sleep(0.01)

我们的 OLED 显示屏是一个 I2C 设备,所以你会注意到,在脚本的开头,我们将两个 GPIO 引脚定义为 SDA (GPIO 20) 和 SCL (GPIO 21)。

Pico有两条I2C总线,你可以使用几种不同的GPIO引脚来连接它们。但它们并不是随便的引脚,例如某些引脚被指定为总线0的SDA,只有它们才能用于SDA总线0。

然后我们使用机器库的I2C函数定义一个I2C连接。我们需要给它提供以下参数。

– I2C总线号,在我们的例子中是0。

– SDA引脚

– SCL引脚

– I2C总线频率–在我们的例子中是400KHz。

然后我们添加OLED库,并创建一个I2C OLED对象。我们将大小参数和I2C连接信息传递给它。

注意,我们没有传递I2C地址。SD1306 OLED显示器有一个固定的I2C地址,所以我们不需要指定它。

不过,我在这里添加了一行与显示器无关的内容,但可以让你扫描I2C总线,并打印出它发现占用的地址。请注意,在Shell中打印出来的是十进制,而不是你更可能习惯看到的十六进制。

回到OLED脚本!

我们开始在显示屏上打印,几行文字。注意我们如何指定每行开始的像素位置。

实际上,我们并没有直接打印到显示屏上,而是将数据发送到一个缓冲区。oled.show()这一行将把该缓冲区的数据传输到显示器上。

在打印完欢迎信息并按住它四秒钟后,我们再执行oled.fill(1)。这将打开显示器中的每一个像素,或者更准确地说,是缓冲区中的每一个像素。然后我们做一个oled.show()来显示填充。

我们将填充物保持在显示屏上两秒钟,然后执行oled.fill(0),当我们显示它时,它将关闭显示屏中的每个像素。

现在进入True循环。

我们再次输入一些文本,经典的 “Hello World”。但我们没有进行 “显示 “来显示它,而是开始一个for-loop。在这个循环中,我们使用led.scroll(1,0)将显示水平移动1像素(垂直移动0像素,这就是另一个参数)。

然后我们在屏幕上显示,然后休眠一段很短的时间。然后我们再做一次。

结果将是显示屏在屏幕上滚动。你可以在for-loop中使用参数来改变它。

将脚本加载到你的Pico上,然后观看显示。你应该看到欢迎文字,然后是显示填充,然后是空。之后,只要你让实验运行,滚动的 “Hello World “就会继续。

驱动电机

微控制器比较流行的应用之一是驱动一个或几个直流电动机。

这是通过使用H-Bridge来实现的,H-Bridge是一种功率晶体管或MOSFET的排列方式,可以处理电机电流,同时允许你控制电机的方向和速度。

我们将只用一个电机来实现这一点。我们将使用TB6612FNG H-Bridge和树莓派 Pico来控制一个小型直流电机。

TB6612FNG H-Bridge

TB6612FNG H-Bridge是我们之前使用过的,一款基于MOSFET的H-Bridge,相比老款备用的L-298N有很多性能上的优势。

该设备其实有两个通道,我们只用通道A来演示。

通道A有三个输入。

– AI1 – 方向和模式

– AI2 – 方向和模式

– PWMA – 一个PWM输入,用于控制电机速度。

在它们之间,AI1和AI2引脚控制电机方向和模式。模式包括短制动和停止模式。在我们的简单演示中,我们将只处理方向模式。

TB6612FNG H-Bridge在板子的另一侧还有电源和电机的连接。

下面是我们将使用TB6612FNG H-Bridge和树莓Pico的连接方式。

请注意,由于我使用的是6V电机,我已经为它提供了一个6V电源。不要试图使用Pico的输出电压来为你的电机供电,单独的电源是必要的。我使用了四节AA型电池,这是一种简单而安全的安排。

电机的极性其实并不重要,它只是决定了哪条路是向前的,哪条路是向后的。

一旦它被全部连接起来,我们就需要一些代码来运行它。我建议这样做。

# 树莓派 Pico Motor Test # motor-test.py # POT – Pico GPIO 26 ADC0 – Pin 32 # RED BUTTON – Pico GPIO 15 – Pin 20 # BLACK BUTTON – Pico GPIO 2 – Pin 4 # RED LED – Pico GPIO 10 – Pin 14 # GREEN LED – Pico GPIO 11 – Pin 15 # BLUE LED – Pico GPIO 14 – Pin 19 # DroneBot Workshop 2021 # https://dronebotworkshop.com import machine import utime potentiometer = machine.ADC(26) mtr_AI1 = machine.Pin(8, machine.Pin.OUT) mtr_AI2 = machine.Pin(7, machine.Pin.OUT) mtr_PWMa = machine.PWM(machine.Pin(6)) button_red = machine.Pin(15, machine.Pin.IN, machine.Pin.PULL_DOWN) button_black = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP) led_red = machine.Pin(10, machine.Pin.OUT) led_green = machine.Pin(11, machine.Pin.OUT) led_blue = machine.Pin(14, machine.Pin.OUT) led_red.value(0) led_green.value(0) led_blue.value(1) mtr_PWMa.freq(50) mtr_AI1.value(1) mtr_AI2.value(0) while True: mtr_PWMa.duty_u16(potentiometer.read_u16()) if button_red.value() == 1: mtr_AI1.value(0) mtr_AI2.value(1) led_red.value(1) led_green.value(0) led_blue.value(0) if button_black.value() == 0: mtr_AI1.value(1) mtr_AI2.value(0) led_red.value(0) led_green.value(1) led_blue.value(0) utime.sleep(0.25)

我们要利用电位器、两个开关和RGB LED,以及电机控制器。电位器将控制电机的速度,开关将控制电机的方向,而LED将用彩色指示灯显示当前的方向。

我们使用我们的之前的两个库,并像以前一样设置电位器。

接下来,我们将Pico与TB6612FNG H-Bridge的连接定义为输出。GPIO 6上的PWMA输出被定义为PWM,它将控制电机速度。

LED和按钮的设置与之前相同。

PWM频率设置为50Hz,这是一个任意的选择。随意实验一下,看看是否能提高电机性能。

电机AI1和AI2输入被设置为正向旋转,所以电机将以正向启动。请注意,当我们启动时,RGB LED的蓝段也会被打开。

在True循环中,我们读取电位器的值,并将其传递给电机PWM信号,以控制电机的速度。我们还要看按钮的状态。

如果红色按钮被按下,我们设置AI1和AI2信号,使电机反转。我们也会点亮红色LED段。

如果黑色按钮被按下,我们设置电机方向正向,并打开绿色LED段。

加载、检查代码。它应该用一个蓝色的LED启动,你应该能够控制电机的速度。按下按钮可以控制方向,还可以改变 LED 的颜色。

Pico Everything 演示

剩下的就是把所有的东西放在一起做一个大的最终演示。这一点我们已经做得不远了,因为在上一个脚本中,我们使用了所有的东西,除了OLED显示屏。

所以让我们把OLED显示屏添加到这个组合中。下面是我们需要做的代码。

# 树莓派 Everything Test # everything.py # POT – Pico GPIO 26 ADC0 – Pin 32 # RED BUTTON – Pico GPIO 15 – Pin 20 # BLACK BUTTON – Pico GPIO 2 – Pin 4 # RED LED – Pico GPIO 10 – Pin 14 # GREEN LED – Pico GPIO 11 – Pin 15 # BLUE LED – Pico GPIO 14 – Pin 19 # DroneBot Workshop 2021 # https://dronebotworkshop.com import machine import utime potentiometer = machine.ADC(26) mtr_AI1 = machine.Pin(8, machine.Pin.OUT) mtr_AI2 = machine.Pin(7, machine.Pin.OUT) mtr_PWMa = machine.PWM(machine.Pin(6)) button_red = machine.Pin(15, machine.Pin.IN, machine.Pin.PULL_DOWN) button_black = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP) led_red = machine.Pin(10, machine.Pin.OUT) led_green = machine.Pin(11, machine.Pin.OUT) led_blue = machine.Pin(14, machine.Pin.OUT) sda=machine.Pin(20) scl=machine.Pin(21) i2c=machine.I2C(0, sda=sda, scl=scl, freq=400000) from ssd1306 import SSD1306_I2C oled = SSD1306_I2C(128, 32, i2c) oled.text(‘Pico Motor Test’, 0, 0) oled.show() utime.sleep(2) led_red.value(1) led_green.value(0) led_blue.value(0) utime.sleep(2) led_red.value(0) led_green.value(1) led_blue.value(0) utime.sleep(2) led_red.value(0) led_green.value(0) led_blue.value(1) mtr_PWMa.freq(50) mtr_AI1.value(1) mtr_AI2.value(0) while True: speedvalue = int((potentiometer.read_u16())/500) mtr_PWMa.duty_u16(potentiometer.read_u16()) if button_red.value() == 1: mtr_AI1.value(0) mtr_AI2.value(1) led_red.value(1) led_green.value(0) led_blue.value(0) if button_black.value() == 0: mtr_AI1.value(1) mtr_AI2.value(0) led_red.value(0) led_green.value(1) led_blue.value(0) oled.fill_rect(1,15,speedvalue,25,1) oled.show() oled.fill_rect(1,15,speedvalue,25,0) utime.sleep(0.25)

现在你应该能认出这段代码的大部分内容了,基本上就是之前的脚本,加上了I2C OLED显示屏的库和设置。除此之外,前几行都是一样的,都是LED颜色的序列,一切设置好后,会有一个Display print。

在True循环中,我们看到正在计算一个名为 “speedvalue “的整数。这个变量将用于设置OLED上条形图显示的大小。

红色和黑色的按钮和之前的操作完全一样。

然后,OLED在其标题线下画一个矩形,并填入矩形。矩形的长度由 “speedvalue “决定,所以随着速度的增加,矩形会变长。

从某种意义上说,我们是把OLED当做一个粗略的速度指示器,或者说是一个速度表!

装上所有的东西,看演示效果。它的操作应该和之前的实验一样,只是这次我们除了有一个显示电机速度的显示器外,还有一个指示其方向的RGB LED。

在没有主机的情况下运行

到目前为止,我们所做的一切都是从 Thonny IDE 将程序加载到 Pico 上运行的。

但是,一旦你开发了程序,你就会希望它能够独立运行,由 microUSB 端口或通过 Pico VSYS 电源输入供电。

你的程序或程序已经存储在 Pico 上。那么我们如何让它在开机时运行程序呢?

答案是,我们更改程序名称!

主程序 main.py

当 Pico 启动时,它会查找名为 main.py 的程序。如果它找到了它,就会加载它并在启动时运行它。

因此,如果你想让你的程序在无人看管的情况下运行,你需要将其保存为main.py。稍后,如果你愿意,你可以将main.py改成其他程序,或者完全删除它。

首先将你希望在启动时运行的程序加载到Thonny IDE中。现在点击 “文件”,然后选择 “另存为”。

你会被问到是否要保存在本地计算机上或Pico上,你肯定要保存在Pico上。

现在把你的程序保存为 “main.py”。就像这样,全部用小写。

现在从电脑上拔下 Pico 的插头,并将其插入合适的电源,如 USB 适配器。你会看到Pico重新开机,并运行你保存为 “main.py “的程序。

结束语

这显然只是树莓派Pico的开始。

我很希望看到PlatformIO和Arduino IDE能够为树莓派 Pico提供支持,因为目前为Pico创建C++程序的方法有些繁琐,特别是对于初学者来说。

但它是进入MicroPython的一个很好且廉价的入口,你会在这里看到更多的东西。

所以尽快拿起Pico开始实验吧!

资源简介

Pico代码 – 本文中使用的所有MicroPython代码,放在一个方便的ZIP文件中。

树莓派 Pico – 树莓派 Pico的官方公告页面。

Pico Pinout – Pico Pinout的树莓派 PDF文件。

Pico Datasheet – 包含Pico技术规格和评级的PDF文档。

RP2040 Datasheet – 包含RP2040微控制器所有规格的PDF文件。警告,这是一个非常大的文档

Pico MicroPython SDK – 在树莓派Pico上使用MicroPython的良好PDF指南。

Pico C++ SDK – Pico上的C++的PDF指南。这也是一个非常大的文档。

译文首发于DF创客社区:https://mc.dfrobot.com.cn/thread-308442-1-1.html

原文链接:https://dronebotworkshop.com/pi-pico/

3D 打印的树莓派蜘蛛机器人

MAKER: Morrisl4/译:趣无尽(转载请注明出处)

这个四足蜘蛛机器人以树莓派作为「大脑」,身躯和四肢由 3D 打印。无需定制电路板,初学者即可完成组装。不仅如此,教程还包含一段将近一个小时的组装视频。这对于想了解树莓派、Python 编程的朋友来说是非常不错的上手项目。

组件清单

Raspberry Pi 3B+/4B × 1

500万像素 OV5647 Pi 摄像头模块 × 1

POWERADD 5000mAh 电源 × 1

PCA9685 16 通道 12 位 PWM 伺服电机驱动 × 1

LM2596 降压转换器 DC-DC 降压模块 × 1

MG90S 伺服电机 × 12

3.7v 锂电池(700mAh) × 4

拨动开关 × 1

跳线 × 若干

M3螺母和螺栓 × 若干

3D 打印组件

需要打印的零件清单:

1 x Body(身体)

1 x Joint 1(关节1)

1 x Joint 2(关节2)

1 x Joint 3(关节3)

1 x Joint 4(关节4)

1 x Thigh 1(大腿1)

1 x Thigh 2(大腿2)

1 x Thigh 3(大腿3)

1 x Thigh 4(大腿4)

1 x Calf 1(小腿1)

1 x Calf 2(小腿2)

1 x Calf 3(小腿3)

1 x Calf 4(小腿4)

1 x 树莓派摄像头支架

1 x 上盖

4 x 足尖(粘)

4 x 足尖(光滑)

每条腿由三个部分组成:关节、大腿、小腿。为了便于组装,STL 文件都做了命名和编号。

可在本项目文件库下载:

https://make.quwj.com/project/349

使用 PLA 材料,3D 打印所有的文件。你可以一次打印所有关节的零件,大腿和小腿也可以一起打印,如图所示。而打印身体、关节、大腿、摄像头支架在打印时需要支撑。

安装树莓派

推荐使用 2GB 内存以上的树莓派 + Raspberry Pi OS 桌面版。为树莓派安装好系统,参考:

使用 Etcher 给 SD 卡安装树莓派系统

通过配置 WiFi,让树莓派接入网络,参考:

无屏幕和键盘配置树莓派WiFi和SSH

开启 SSH,使用 PuTTY 登录树莓派终端。传输文件和电影可以通过 SFTP,使用 FileZilla 即可。

开启 VNC 并使用 VNC Viewer 来登录树莓派,参考:

树莓派 VNC Viewer 远程桌面配置教程

组装机器人

组装全过程视频。(视频长 51 分钟,请酌情切换到 WIFI 下观看)

特别说明:

1、某些零件可能需要进行打磨才可以装配在一起。你不一定完全依照视频中的步骤组装,不过建议先测试好电路部分,测试好之后再组装 3D 零件。

2、每个伺服电机的接线图和表格下面有提供。

3、如果你对 4 节锂电池的连接感兴趣,这里说明一下。这是一组两节 3.7V 锂电池,串联成 7.4V 电池组。通过另一组同样的并联,每个锂电池 700mAh,最终成为 7.4V 1400mAh 电池组。串联增加电压,并联扩充容量。机器人上有两块电源,锂电池组给伺服电机供电,移动电源独立为树莓派供电。

下面是用到的软件和命令:

WinSCP: https://winscp.net/eng/download.php

Adafruit_Python_PCA9685 模块:

sudo pip3 install adafruit-pca9685

Pygame 模块:

sudo pip3 install pygame

程序源文件可在本项目文件库下载:

https://make.quwj.com/project/349

完成

参考视频操作下来,就可以完成组装了。希望你可以从中学到东西,体验到乐趣!

你可以在此机器人平台上做一些有趣的扩展、升级。例如增加一个 HC-SR04 超声波传感器,在本项目的文件库中已经提供了相应的 STL 文件。通过编程即可实现让机器人自主行走,绕开障碍物。

通过加装 MPU-6050 传感器,还可以让机器人实现自平衡。引入 OpenCV 让机器人具有计算机视觉功能……

尽情发挥你的想象力吧!

via

MCC 128 – 基于树莓派®的16位电压测量HAT模块发布

诺顿,马萨诸塞州 – 2021年1月11日 – MCC(Measurement Computing Corporation)发布MCC 128基于树莓派的电压测量 HAT。MCC 128 具有16位分辨率和多档可选量程——高精度测试的理想选择。它包含了8路单端和4路差分模拟输入通道,采样率高达100kS/s。

最多可在单块树莓派上叠加8个MCC 128模块——提供64通道的数据采集,最大总采样率可达320kS/s。MCC提供了丰富的DAQ HAT模块,可以让客户在基于树莓派的解决方案里,添加电压,热电偶或振动输入和数字I/O的功能。

MCC 128提供两个可用版本。MCC 128为螺丝接线端信号连接器。对于想要安装其它连接器的用户,MCC 128-OEM提供了未安装信号连接器的版本。

特点

16位电压输入

支持8路单端和4路差分输入模式

最大采样率达100 kS/s (堆叠板总采样率达320 kS/s)

多种输入量程

内置缓存器支持高速采集

支持外部采样时钟输入

外部数字触发输入

螺丝端子连接

最多可将8个MCC HAT叠加至树莓派®

软件

可在GitHub上获取MCC DAQ HAT全套开源库

操作系统

Linux®/Raspbian

可编程API

C, C++, Python

了解详情:http://china.mccdaq.com/DAQ-HAT/MCC-128.aspx

所有MCC的HAT模块,均提供开源且易于使用的C/C++®和Python™ 函数库和范例,让您可以快速搭建稳定可靠的测试测量系统。该库可从GitHub下载。 还提供了全面的API和硬件相关文档。

关于Measurement Computing

Measurement Computing设计和制造易于使用,轻松集成和快速支持的数据采集设备。 包含的软件选项非常丰富,可供程序员和非程序员使用。Measurement Computing提供免费的技术支持,有限终身保修和低成本。Measurement Computing是DAQ设备的最佳选择 。

获取更多关于Measurement Computing的信息,请访问官网:china.mccdaq.com

树莓派 ZeroW + Openwrt 如何驱动 RNDIS Ethernet-Gadget 网卡

大家好,我是 Archer,那个困扰我几年之久的问题,终于解决了。

Openwrt 的 gadget-eth 网卡,在19.07.3版本,终于能用啦!(Ohhhhhhhhhh!)

这里我仅仅验证了19.07.3版本,19.07.4版本应该没问题。

首先,搞一个树莓派ZW,一个OTG的USB分线器,还有一个USB以太网卡,一个键盘,一个屏幕,另一台电脑。这就是调试这个用法所需要的设备。

然后,去下载这个系统镜像,然后往一张大于512M的TF卡上,烧录这个系统。烧录好之后,不要先拔出储存卡,然后下载这些驱动包,放在TF卡的引导分区里面(Fat32那个分区)。

kmod-usb-net_4.14.180-1_arm_arm1176jzf-s_vfp.ipk

kmod-mii_4.14.180-1_arm_arm1176jzf-s_vfp.ipk

最后一个视乎你有什么以太网卡,看芯片,下载其中一个包:

kmod-usb-net-asix-ax88179_4.14.180-1_arm_arm1176jzf-s_vfp.ipk(任天堂Switch主机和安卓手机等设备通用网卡)

kmod-usb-net-asix_4.14.180-1_arm_arm1176jzf-s_vfp.ipk(任天堂Wiiu主机及安卓手机等设备通用网卡)

kmod-usb-net-rtl8152_4.14.180-1_arm_arm1176jzf-s_vfp.ipk(小螃蟹USB2和USB3网卡的通用驱动)

kmod-usb-net-dm9601-ether_4.14.180-1_arm_arm1176jzf-s_vfp.ipk(电脑城坑爹10M低速网卡)

kmod-usb-net-mcs7830_4.14.180-1_arm_arm1176jzf-s_vfp.ipk(MCS7830网卡的驱动)

然后把储存卡插到树莓派ZW上,街上网卡键盘屏幕,然后通电开机。

开机之后,首先切换到fat32分区。

cd /boot

然后再安装放在引导分区里面的三个驱动包(第三个驱动包根据自己的网卡自选)

opkg install kmod-usb-net_4.14.180-1_arm_arm1176jzf-s_vfp.ipk kmod-mii_4.14.180-1_arm_arm1176jzf-s_vfp.ipk kmod-usb-net-dm9601-ether_4.14.180-1_arm_arm1176jzf-s_vfp.ipk

安装完毕之后,可以通过修改Lan口参数:

vi /etc/config/network

然后修改(此处请按照自家网络实际参数进行设置,此处仅供参考)

config interface ‘lan’ option type ‘bridge’ option proto ‘static’ option netmask ‘255.255.255.0’ option ip6assign ’60’ list dns ‘180.76.76.76’ option ipaddr ‘192.168.254.1’ option ifname ‘eth0’

修改之后,再执行更换软件源的指令

sed -i ‘s_downloads.openwrt.org_mirrors.tuna.tsinghua.edu.cn/openwrt_’ /etc/opkg/distfeeds.conf

这样重启之后,把网卡的网线跟另一台电脑连接之后,电脑就可以通过浏览器输入192.168.254.1来网页遥控树莓派ZW。

可以网页控制树莓派之后,首先去network ——firewall处,去修改防火墙配置,找到Zone,把wan→REJECT处的两处reject改成accept,这样就可以上层网络访问路由器了。

然后去network —— wireless处,找到Scan选项,扫描自家的WiFi,然后配置,加入,这样就联网成功了。之后把树莓派和电脑之间连接的网线拔开,把自己的电脑连接上层的网络,然后扫描IP地址,找到树莓派ZW的IP,浏览器输入IP继续网页遥控树莓派ZW。

进去网页控制之后,去network —— interfaces处,编辑LAN口,找到physical setting,把eth0网卡给取消掉,再去 system——software 处,去installed列表,把USB网卡的三个驱动包给删除掉,然后点update lists,去更新软件列表,然后安装一下软件包 kmod-usb-gadget kmod-usb-gadget-eth kmod-usb-dwc2。

修改 /boot/config.txt,往文本末尾加一行:

dtoverlay=dwc2

再修改/etc/rc.local,在exit0前加一行:

modprobe g_ether

下次开机,就会自动加载gadget-eth网卡驱动,然后把ZW的OTG口接上安卓手机数据线连到电脑,你的电脑就能感知到RNDIS设备了(如果Win10,还需要驱动)

接下来只要开着网页,把usb0接口添加到lan界面,电脑就可以通过树莓派上网了。

这个东西其实还有高阶玩法,例如安装aircrack-ng ,reaver等软件,剩下的你们都懂,或者钓鱼截包等都可以。由于采用openwrt这种轻量级系统,系统占用资源降到最低,可以用于更加高阶的需求,是一件给高手的玩具,虽然有基于kali的开源项目P4wnP1,但多一个openwrt的选项未尝不好,而且openwrt跟电脑的连接其实更加灵活,除了g_ether网卡模式以外,还可以安装kmod-usb-gadget-serial串口驱动包和kmod-usb-gadget-mass-storage储存模式等可选,这样一件玩具,希望大家喜欢。

我想把这玩意命名为大师网卡,因为塞尔达玩久了,发现强力的不是大师之剑,而是能打通剑之试炼的玩家。

附:

最后附上 Archer 制作好了的系统镜像文件,可以直接烧录好给树莓派 ZeroW 使用。

链接: https://pan.baidu.com/s/1UmQml_ltZIFNgg-KxMIVMw 提取码: 13rd

虹科工业树莓派:结合 Codesys 实现软 PLC

1. 简介

虹科工业树莓派RevolutionPi是以树莓派计算模块为核心并进行了工业级封装的模块化智能网关与控制器,能在恶劣的工业环境下运行。其操作系统也是优化后的树莓派Raspbian系统,带有实时补丁,能更好地满足工业场合的实时性要求。

Codesys是一款是一种功能强大的PLC软件编程工具,它支持IEC61131-3标准IL 、ST、 FBD 、LD、 CFC、 SFC 六种PLC编程语言,用户可以在同一项目中选择不同的语言编辑子程序,功能模块等。通过在硬件平台上移植Runtime,可以将任何嵌入式设备或基于PC的设备转变为符合IEC 61131-3标准的工业控制器。本文将以RevPi Connect模块为例介绍如何在虹科工业树莓派RevPi上安装Codesys Runtime并进行简单的应用。

2. 所需材料

– RevPi Connect

– PC(预装好Codesys IDE开发环境)

– Codesys Control for Raspberry Pi(可在codesys中国官网下载)

– Codesys Package for RevPi Family

3. 安装Codesys Runtime

在安装Runtime之前首先需要搭建好RevPi运行环境,PC与RevPi处于同一局域网内。

打开Codesys软件,选择工具-》包管理器,安装已经下载好的Codesys Control for Raspberry Pi。安装完成之后就可以在“工具”下找到Update Raspberry Pi,进入可以看到如下界面:

输入RevPi的IP地址以及登录账号名及密码,并选择对应的Codesys Runtime Package,点击Install即可。在安装过程中需要选择单核还是多核模式,由于本次只是演示,所以选择单核模式,稍等一会安装即可完成。

4. 建立工程

点击文件->新建工程,选择新建一个标准工程并将工程命名为RevPiDemo。

在开始编程之前,首先需要安装Codesys Package for RevPi Family。安装方式同样是通过包管理器实现,此处不再赘述。同时在此包文件中也会包含一些工程示例。

包安装完成之后就可以向工程中添加设备了,在Device上右击,选择“添加设备”。选中Connect模块,单击“添加设备”按钮即可。然后关闭此窗口。

然后在新添加的Connect模块上右击,选择“添加设备”,选中其他项->left并添加。

然后再left上右击添加设备即可选择自行添加IO模块。在PiBridge上右击选择“插入设备”即可插入网关模块。

设备添加完成之后,就可以开始编程了。所有已添加的设备相关的变量都可以在Codesys中显示出来并进行配置。

5. 下载程序

程序编写完成之后,需要将程序下载到Connect模块中,在此之前需要安装好Runtime。首先双击Device,点击通讯设置-》扫描网络,选择RevPi即可。

然后点击上方的登录按钮,等待将信息下载到RevPi模块即可。

6. 总结

上面介绍的如何在RevPi上运行Codesys并建立工程的详细步骤。通过Codesys不仅可以实现将RevPi作为软PLC从而利用各种PLC编程语言进行编程外,还可以实现Canopen主站,Ethercat主站等功能。

注:

1. RevPi家族扩展网关模块除DMX外只提供从站模块。

2. Codesys是一款商业软件,需要购买licence才能正常使用,未安装licence的设备有运行时间限制。

树莓派上安装 Java JDK 的方法

Java 是用于构建各种应用程序和系统的最流行的编程语言之一。Java 有两种不同的实现,Oracle Java 和 OpenJDK。其中 OpenJDK 是 Java 平台的开源实现。Oracle Java 具有其他一些商业功能,并且许可仅允许非商业用途。下面介绍如何在树莓派的 Raspbian OS 上安装Java(OpenJDK)。

运行以下命令安装最新的 JDK 版本,目前是 OpenJDK 11 JDK:

sudo apt update sudo apt install default-jdk

安装完成后,通过命令可以检查 Java 版本进行验证:

java -version

输出:

openjdk version “11.0.5” 2019-10-15 OpenJDK Runtime Environment (build 11.0.5+10-post-Raspbian-1deb10u1) OpenJDK Server VM (build 11.0.5+10-post-Raspbian-1deb10u1, mixed mode)

安装 Java 8

Java 8 目前依然被广泛使用。如果你需要 Java 8,安装命令为:

sudo apt update sudo apt install openjdk-8-jdk

检查 Java 版本:

java -version

多个 Java 版本并不会冲突,如果需要设置默认的版本,可以使用下面的方法。运行 java -version 命令确认默认的版本。如果需要修改默认版本,可以用 update-alternatives 工具:

sudo update-alternatives –config java

您将看到已安装的 Java 版本的。

There are 2 choices for the alternative java (providing /usr/bin/java). Selection Path Priority Status ———————————————————— * 0 /usr/lib/jvm/java-11-openjdk-armhf/bin/java 1111 auto mode 1 /usr/lib/jvm/java-11-openjdk-armhf/bin/java 1111 manual mode 2 /usr/lib/jvm/java-8-openjdk-armhf/jre/bin/java 1081 manual mode Press to keep the current choice[*], or type selection number:

输入要设置的默认版本的版本号,然后按回车。

如果安装了多个 JDK 版本,要设置 JAVA_HOME 环境变量的话,则需要编辑 /etc/environment 文件:

sudo nano /etc/environment

假设要将 JAVA_HOME 设置为 OpenJDK 11,那么可以在文件末尾添加:

JAVA_HOME=”/usr/lib/jvm/java-11-openjdk-armhf/bin/java”

后面的路径就是 update-alternatives 命令所输出的。

然后运行命令:

source /etc/environment

最后,要卸载 default-jdk 软件包,只需运行:

sudo apt remove default-jdk

树莓派 Pico:树莓派首款微控制器级产品

今天,树莓派基金会发布了首款微控制器级产品:Raspberry Pi Pico。

基于一款全新的 RP2040 芯片构建,售价仅 4 美元。

如果你使用过 Arduino 或一些支持 MicroPython 的开发板的话,应该会对这类微控制器产品(MCU)很熟悉。超低功耗、极低的 I/O 延迟、低廉的价格和简单的控制方法,让树莓派 Pico 和其他 MCU 一样容易上手,并且能获得广泛的应用。

树莓派 Pico 上的 RP2040

RP2040 芯片是 7×7mm QFN-56 封装的,具体规格参数如下:

– 双核 Arm Cortex-M0 + @ 133MHz

– 芯片内置 264KB SRAM 和 2MB 的板载闪存

– 通过专用 QSPI 总线支持最高 16MB 的片外闪存

– DMA 控制器

– 30 个 GPIO 引脚,其中 4 个可用作模拟输入

– 2 个 UART、2 个 SPI 控制器和 2 个 I2C 控制器

– 16 个 PWM 通道

– USB 1.1 主机和设备支持

– 8 个树莓派可编程 I/O(PIO)状态机,用于自定义外围设备支持

– 支持 UF2 的 USB 大容量存储启动模式,用于拖放式编程

树莓派基金会表示,树莓派 Pico 是与 MicroPython 的创建者 Damien George 合作开发的。可以看出整个开发板的设计上吸收了不少 pyboard 的优秀特性。

另外 Adafruit 和 Pimoroni 也参与到了 RP2040 生态之中。它们推出了类似的产品:

Adafruit Feather RP 2040

Adafruit ItsyBitsy RP 2040

Arduino Nano RP2040 Connect

Pimoroni PicoSystem

Pimoroni Pico Explorer Base

SparkFun Thing Plus – RP2040

SparkFun MicroMod RP2040 Processor

SparkFun Pro Micro – RP2040

相信树莓派 Pico、RP2040 的生态会逐步丰富起来。

BUY LINK:http://link.nxez.com/buy/raspberry-pi-pico

快速上手指引:树莓派 Pico 上手指引(中文版)

基于树莓派 MCC 172 的神经肌肉生物力学测试系统

威斯康星大学麦迪逊分校(University of Wisconsin-Madison)的神经肌肉生物力学实验室(Neuromuscular Biomechanics Laboratory)对人体运动的生物力学和神经肌肉协调进行了研究,并将其应用于骨科和康复领域。

使用计算机模拟来表征肌肉腱动态,估计内部负荷,并测试指导运动控制的原理。研究的总体目标是为临床治疗和预防限制运动功能的损伤建立科学依据。

挑战

剪切波张力测定法是一种非侵入性技术,可促进运动过程中肌肉肌腱负荷的测量。传统上,它是通过台式系统完成的,该台式系统将使用范围限制在实验室环境中。

基于树莓派的解决方案允许在便携式包装中执行数据采集,从而解放了探索现实世界中生物力学行为的实验。

解决方案

剪切波张力计是首创的传感器,它可以在动态活动(例如步行和跑步)期间无创地跟踪体内的肌腱力。如果传感器可以在非实验室环境中便携式和可穿戴,则可以极大地扩展张力计的应用范围。高速,可靠的数据采集对于可穿戴式张力计的成功至关重要。

对于一个张力计,一个MCC 172 —— 基于IEPE传感器测量HAT,将以51,000Hz的频率完成两个单轴加速度计的采样。对于多张力计实验,两个HAT用于同步获取两个肌腱的数据。

在每个收集期间,通过开环压电控制器(MDT694B,Thorlabs,Newton,NJ)以50Hz方波驱动压电驱动(PK4JQP2,Thorlabs,Newton,NJ)。加速度计阵列由两个微型加速度计(352C23型,纽约州Depew的PCB Piezotronics)安装在硅胶模具(Mold Star 15 SLOW,Smooth-On,Macungie,PA)中,相距10mm。加速度计的数据以100kHz的频率采集,然后使用具有150和5000Hz截止频率的滤波器进行滤波。计算两个加速度计到达波之间的时间,通过将加速度计之间的距离(10毫米)除以时间延迟来计算剪切波速度。对每个方波上升沿信号执行此分析会产生50Hz的肌腱波速度信号。

具体的理论方法参考:

https://www.frontiersin.org/articles/10.3389/fspor.2020.00069/full

该系统由树莓派4B,两个MCC 172和两个单轴加速度计组成。Pololu Wixel是一种具有2.4GHz无线电和USB接口的通用可编程模块,可远程支持触发。

使用Python™脚本对该系统进行了编程,以实现多HAT连续采集。数据的后处理则是在MATLAB®中完成的。

成果

整套系统是一个小型便携式解决方案,允许研究人员在实际环境中测量肌腱的生物力学行为。

树莓派和MCC 172的体积小巧,使研究人员能够创建轻巧且可穿戴的DAQ解决方案,以测量步行和跑步过程中的动态活动。

达里尔·塞伦(Darryl Thelen)

机械工程系(Department of Mechanical Engineering)

威斯康星大学麦迪逊分校(University of Wisconsin-Madison)

1513 University Ave

Madison, WI 53706

关于Measurement Computing

Measurement Computing设计和制造易于使用,轻松集成和快速支持的数据采集设备。 包含的软件选项非常丰富,可供程序员和非程序员使用。Measurement Computing提供免费的技术支持,有限终身保修和低成本。Measurement Computing是DAQ设备的最佳选择 。

获取更多关于Measurement Computing的信息,请访问官网:china.mccdaq.com

硬核 WiFi/4G/5G 网络遥控车制作教程

来自 EsonWong 的推荐投稿。

本教程介绍使用树莓派和遥控车制作一台可以通过网络控制的遥控车。软件使用我开发的 network-rc。

材料

树莓派 3B+ (300 元)

树莓派摄像头 (15 元) / ps3 摄像头 (40 元)

移动电源 (60 元) / USB 输出降压模块 (?元)

环奇 743A (286 元,某宝上找不到了)

杜邦线(公对公 x1, 公对母 x4) (3 元)

其它固定材料

树莓派软件安装运行

安装 network-rc

树莓派安装 buster 版本以上系统连接摄像头,连接 wifi。

注意:最新系统存在兼通性问题,使用此版本系统http://downloads.raspberrypi.org/raspbian/images/raspbian-2020-02-07/

网络上有很多树莓派系统安装教程,请自行搜索。

在树莓派上下载 network-rc 软件

wget https://network-rc.esonwong.com/download/network-rc.tar.gz # 备用地址下载 wget https://esonwong.synology.me:5011/download/network-rc.tar.gz # 解压文件 tar -zxvf network-rc.tar.gz # 运行程序 sudo ./network-rc/node ./network-rc/index.js

用同一局域网网下的浏览器里打开 http://树莓派的ip地址:8080 即可看到控制界面

环奇 743A 改装

如果你是用其它车的话,只要舵机和电调的接线和控制信号通用即可(仅支持三线的电调和舵机)。

1. 取下舵机和电调与接收机之间的连线

2. 连接到树莓派

树莓派关机。

1) 将舵机和电调的正极线(VCC\红色) 和 电调的正极线用公对公杜邦线连接起来,舵机从电调上取电。

2) 使用公对母杜邦线将舵机的信号线(PWM\白色或黄色) 连接到树莓派的 GPIO 12 (编号 32\PWM0)

3) 使用公对母杜邦线将电调的信号线(PWM\白色或黄色) 连接到树莓派的 GPIO 13 (编号 33\PWM1)

4) 使用公对母杜邦线将舵机和电调的地线(Ground\黑色或棕色) 连接到树莓派的 GPIO Group,建议连接到编号 30 和 34,方便理线。

启动

树莓派接通电源,开机,运行软件。小车接通电源,开机。打开浏览器,开始享用吧。

https://www.bilibili.com/video/BV1iK4y1r7mD

网络遥控车互联网控制教程

要实现远程控制,必须让遥控车在互联网上可以访问遥控车。下面教大家如何让遥控小车接入移动互联网实现 4G/5G 网络无限距离遥控。

4G/5G 网络连接

为了让网络遥控车接入互联网,按[WiFi/4G/5G 网络遥控车制作教程]做好遥控车之后,要让小车上的树莓派连接到 4G/5G 网络。

UBS 4G/5G 网卡

USB 4G/5G 网卡是现在最方便的选择。我使用的是华为的 E8372h。插上树莓派就能联网

WiFi

你也可以用 4G/5G 手机(或者 4G/5G 路由器)来连接互联网。

开启手机 Wi-Fi 热点:

把手机安装到车上,树莓派上连接手机 Wi-Fi 热点。

树莓派连接 Wi-Fi 的方法请自行搜索。

此时树莓派是没有公网的 ip 地址的,还不能通过互联网连接到遥控车。

外网访问

我们通过使用 frp 软件实现互联网对遥控车的访问。 network-rc 于 v0.5.0 版本里内置了 frp 客户端和作者提供的 frp 服务的配置。

使用下面的命令运行即可开启网络穿透功能(不需要{}):

sudo ./network-rc/node ./network-rc/index.js -f -o 9011 –tsl -p {你想设置的控制界面登陆密码}

由于可通过互联网访问,务必设置连接密码。

成功后即可通过 http://home.esonwong.com:9011 (9011 替换成你设置的端口号) 访问你的遥控车控制界面。

开机启动 network-rc

为了方便接上电源即可控制遥控车,我们将 network-rc 设置为开机启动。

增加 network-rc 服务,在 /etc/systemd/system/ 目录下新建 network-rc.service 文件,替换下方文本里的 network-rc 路径和密码(不需要{})保存到文件里。

创建和编辑 /etc/systemd/system/network-rc.service 文件需要 root 。如果用图形界面使用 sudo pcmanfm

[Unit] Description=network-rc After=syslog.target network.target Wants=network.target [Service] User=root Type=simple ExecStart={network-rc文件夹路径}/node {network-rc文件夹路径}/index.js -f -o {访问端口} -p {你想设置的控制界面登陆密码} –tsl # 比如 ExecStart=/home/pi/network-rc/node /home/pi/network-rc/index.js -f -o 9011 -p password –tsl Restart= always RestartSec=1min [Install] WantedBy=multi-user.target

设置开机启动服务:

sudo systemctl enable network-rc.service

network-rc 将在树莓派开机时和网络切换时自动运行。

查看服务状态:

sudo systemctl status network-rc.service

如果更新了文件需要运行:

sudo systemctl reload network-rc.service sudo systemctl enable network-rc.service sudo systemctl start network-rc.service

4G 网络下的实际遥控效果

https://www.bilibili.com/video/BV14p4y1X7qf

项目地址:https://github.com/itiwll/network-rc

原文链接、视频教程。

交流微信群

入群方法添: 加微信 EsonWong_ 备注 Network RC

拆解一下新发布的树莓派 400

近期树莓派基金会发布了树莓派 400。这款产品本质上是把树莓派主板集成到键盘的外壳中的电脑。

当然,它并不是简单地把树莓派 4B 给封装进去,为此厂家重新设计了电路和 PCB。

你只要一根 HDMI 线、一个 5V 电源适配器外加一个鼠标,连上显示器,树莓派 400 就成了一台标准的桌面电脑。

从正面看树莓派 400 和之前的树莓派官方键盘,基本上没有什么不同,唯一的区别是 F10 滚动锁键现在变成了电源键,滚动锁指示灯现在变成了电源/活动指示灯。

侧面,树莓派 400 的接口更多。有两个 USB 3.0、一个 USB 2.0,两个支持 4K60 输出的micro HDMI 接口,一个千兆网卡(现在支持PoE),一个供电用的 USB-C,重要的是还有40pin 的 GPIO 接口。

树莓派 400 裸机价格 70 美元,官方还特别推出了 100 美元的套件。

100 美元的树莓派 400 套件包含:

树莓派 400 (1.8GHz 4核CPU, 4GB内存)

一张 16GB 闪迪 microSD卡

官方 USB-C 电源

官方鼠标

micro-HDMI 转 HDMI 线

树莓派官方入门指南

拆解

树莓派 400 底部没有任何螺丝或其他紧固件,与普通键盘的区别是做了一些通风口和较大的橡胶脚。

拔掉键盘与主板的连接器,我们首先注意到这块巨大的散热片,在左上角有一个小小的导电垫,衔接着以太网插口、散热片和键盘。

接下来,我们卸下固定散热片的四颗螺丝。这一步需要在拉起的时候前后晃一下,因为它是用一个粘性很强的热胶垫固定在博通 SoC 芯片上的。

把散热器拿出来后,可以看到树莓派 400 与树莓派 4B 的设计区别。

树莓派 400 的主板背面并没有太多的元件,非常简洁。

树莓派 400 使用了和其他支持 WiFi 的树莓派上一样的 PCB 天线来做 WiFi,没有外部组件,一个相当不错的小天线。

性能

树莓派 400 支持树莓派桌面操作系统,以及 Debian、Ubuntu 等第三方 Linux 发行版。

规格方面,树莓派 400 采用了与树莓派 4 类似的四核 64-bit@1.8GHz ARM Cortex-A72 处理器,辅以4GB RAM、Wi-Fi、蓝牙5.1(低功耗蓝牙)、以及千兆以太网。

树莓派 400 的参数并没有太大的改动,相较于树莓派 4B 的 1.5 GHz 频率提高到了 1.8 GHz。由于这块巨型散热片的功劳,有爱好者已经成功将其超频到了 2.2 GHz,运行了几个小时之后,依旧稳定。

结语

树莓派基金会的初衷确实是让可编程的计算机得以以很低的成本到人们手上。

可没想到实际情况与他们的初衷「走偏了」,直接引爆了 MAKER 市场……

自树莓派首个版本发布以来,树莓派被用在了各种眼花缭乱的场景下,甚至在工业和商业领域之中也有见到它的身影。

树莓派 400 的发布,我们看到很多关于「树莓派 400 走偏了」的讨论。和之前我们发过的「拔掉 MacBook,用 8GB 树莓派来办公的体验如何?」得出的结论类似:

如果想用树莓派 400 完全替代我们平时使用的电脑,暂时还是不够的。但对于一部分人来说,树莓派 400 有它的独特优势。

树莓派 400 性能比高(仅需要 5V 电源供电),小巧方便。对于一些平时只需要浏览网页、编辑文档、处理电子邮件、浏览社交媒体,甚至可能会需要做一些轻量级的照片或视频整理的小伙伴们来说,就是一个很好的选择。

树莓派 400 还非常适合教育方面的应用。正如官方网站所说的:

树莓派 400 是所有年龄段学生的完美教育工具。它成本低,便于携带,是家庭学习的理想之选,也是教授编程、物理计算和网络等计算概念的理想之选。

作为自己孩子的第一台学习编程或者 Linux 系统的电脑,树莓派 400 是一个非常不错的选择。

via: https://www.jeffgeerling.com/blog/2020/raspberry-pi-400-teardown-and-review | Jeff、Roy DF创客社区

在工业树莓派中轻松部署您的OPC UA 服务器与客户端

简介

虹科工业树莓派是一款基于树莓派计算模块的开源的模块化智能网关,其全名是RevolutionPi(简称RevPi)。RevPi在计算模块的基础上进行了工业级封装,以实现工业环境的适用性。它取消了不稳定的GPIO接口,通过模块化的DIO以及AIO模块进行扩展。另外它还提供有适用于大多数常见现场总线协议以及工业以太网的网关扩展模块,使得RevPi可以快速集成到您的工业网络中。在软件方面,RevPi基于树莓派的Raspbain系统,并添加了RT(RealTime)补丁, 支持C、python、Node-RED等高级语言编程,并且内置虚拟Modbus RTU/TCP主从站,无需额外扩展网关即可与您的Modbus设备进行连接。

OPC UA是OPC基金会推出的面向工业4.0的接口规范,它具有架构统一、平台独立、安全可靠、可扩展等特点。OPC UA主要解决了语义互操作性问题,在整个OICT融合中扮演了非常重要的角色。虹科工业树莓派作为一款模块化的边缘智能网关,默认是没有配备OPC UA功能的。但由于得益于其平台的开源性,我们可以自己在RevPi上部署OPC UA Server及Client。虹科Matrikon OPC UA SDK是一款允许您简单迅速地添加一个OPC UA服务器到您嵌入式产品中的软件开发工具包。但由于版权的原因,本文使用开源的open62541进行测试。作为开源项目,open62541相对于虹科Matrikon OPC UA SDK具有不标准、效率低等劣势。作为测试Demo,我们可以不考虑这一点,但在实际现场应用中,建议选择使用更加标准的虹科Matrikon OPC UA SDK进行开发。

1.准备

RevPi Core x1

路由器 x1

网线 x1

open62541源码(可从官网下载)

PC x1

2.编译open62541源码

2.1 编译

首先我们需要编译open62541源码,生成对应的.c和.h文件,才能很方便地把open62541集成到我们自己的代码中。

我下载的源码版本是open62541-1.1.2.zip,首先通过命令解压文件:

unzip open62541-1.1.2.zip

然后进入open62541-1.1.2文件夹,创建build目录并进入,输入以下命令调用cmake:

cmake .. -DUA_ENABLE_AMALGAMATION=ON

然后再调用make命令,完成后即可生成以下文件:

2.2 建立Demo

在上一部分,已经通过make命令生成了open62541.c和open62541.h文件。下面我们退出open62541-1.1.2,建立新的文件夹Demo,并将open62541.c和open62541.h文件复制到该文件夹。然后我们就可以在此文件夹中调用open62541编写server及client的程序了。为了方便后续程序编译调试,我们可以先把open62541.c编译一下,运行以下命令:

gcc -c open62541.c -o open62541.o

3.OPC UA Server

下面就正式开始编写server程序了,此部分可以参考open62541官方文档。本文的目的不仅仅是建立一个简单的server,还要结合RevPi特有的虚拟Modbus TCP主站的功能,将读取到的Modbus TCP Slave的数据放入OPC UA Server变量中,以实现一个简单的协议转换功能。

3.1 建立Server程序

新建server.c文件,并写入以下代码:

#include “piControlIf.h” #include “piControl.h” #include “open62541.h” #include #include #include #include #include static volatile UA_Boolean running = true; static void stopHandler(int sig) { UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, “received ctrl-c”); running = false; } uint16_t Read_i16u__Val(char *pszVariableName) { int rc; SPIVariable sPiVariable; SPIValue sPIValue; uint16_t i16uValue; strncpy(sPiVariable.strVarName, pszVariableName, sizeof(sPiVariable.strVarName)); rc = piControlGetVariableInfo(&sPiVariable); if (rc < 0) { printf("Cannot find variable '%s' ", pszVariableName); } if (sPiVariable.i16uLength == 16) { rc = piControlRead(sPiVariable.i16uAddress, 4, (uint8_t *) & i16uValue); if (rc < 0) printf("Read error "); else { return i16uValue; } } else printf("Could not read variable %s. Internal Error ", pszVariableName); } static void addVariable(UA_Server *server) { /* Define the attribute of the myInteger variable node */ UA_VariableAttributes attr = UA_VariableAttributes_default; UA_Int16 myInteger = 0; UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT16]); attr.description = UA_LOCALIZEDTEXT("en-US","modbus data"); attr.displayName = UA_LOCALIZEDTEXT("en-US","modbus data"); attr.dataType = UA_TYPES[UA_TYPES_INT16].typeId; attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; /* Add the variable node to the information model */ UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "modbus.data"); UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "modbus data"); UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId, myIntegerName, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr, NULL, NULL); } static void updateModbusData(UA_Server *server) { UA_Int16 new_value = Read_i16u__Val("Input_Word_1"); UA_Variant value; UA_Variant_setScalar(&value, &new_value, &UA_TYPES[UA_TYPES_INT16]); UA_NodeId currentNodeId = UA_NODEID_STRING(1, "modbus.data"); UA_Server_writeValue(server, currentNodeId, value); } static void beforeReadData(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *nodeid, void *nodeContext, const UA_NumericRange *range, const UA_DataValue *data) { updateModbusData(server); } static void addValueCallbackToModbusDataVariable(UA_Server *server) { UA_NodeId currentNodeId = UA_NODEID_STRING(1, "modbus.data"); UA_ValueCallback callback ; callback.onRead = beforeReadData; UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback); } int main() { signal(SIGINT, stopHandler); signal(SIGTERM, stopHandler); UA_Server *server = UA_Server_new(); UA_ServerConfig_setDefault(UA_Server_getConfig(server)); UA_ServerConfig* config = UA_Server_getConfig(server); config->verifyRequestTimestamp = UA_RULEHANDLING_ACCEPT; addVariable(server); addValueCallbackToModbusDataVariable(server); UA_StatusCode retval = UA_Server_run(server, &running); UA_Server_delete(server); return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE; }

3.2 Server程序分析

下面简单分析一下此Server程序。大概可以分为三个部分Server主程序、添加变量、变量回调。

Server主程序主要包含在main函数中,分为以下几个阶段:

实例化server

配置server,使用默认配置

检测到ctrl+c,server停止运行

删除server

Server的框架搭建好之后需要向server中添加变量,此部分由addVariable函数完成。此函数的作用就是向server中添加一个nodeid为modbus.data的变量。

最后就是将虚拟Modbus TCP Master读取到的数值放入新建的变量中。因为变量的值需要实时更新,这样client读取到的数据才是最新的。但如果重复不断循环写入的话,会造成占用资源过多,所以我们在此处给变量添加一个回调,只有当client读取这个变量的时候才会同步一下数据,以防止资源的不必要浪费。此部分功能是由函数addValueCallbackToModbusDataVariable、beforeReadData、updateModbusData完成的。

另外,为了读取到Modbus TCP Master的数据,我们需要从过程映像中取出变量的值,此处的变量为Input_Word_1。幸运的是,这部分不需要我们从头开始写代码,我们可以调用RevPi piTest命令的源码来实现。因此,我们需要include头文件piControlIf.h和piControl.h。Read_i16u__Val就是调用此头文件里的函数从过程映像中读取Input_Word_1的数值的。

本文不再进行代码的详细剖析,有兴趣的可以结合open62541的官方文档深入了解。下面我们看一下代码的运行结果,使用下面的命令编译serve程序:

gcc server.c open62541.o piControlIf.c -o server && ./server

运行结果为:

可以看到server程序成功在opc.tcp://RevPi32692:4840/运行。

4.OPC UA Client

4.1 建立Client程序

新建client.c文件,并写入以下代码:

#include “open62541.h” #include #include #include static volatile UA_Boolean reading = true; static void stopHandler(int sig) { UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, “received ctrl-c”); reading = false; } int main(int argc, char *argv[]) { UA_Client *client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); /* Connect to a server */ UA_StatusCode retval = UA_Client_connect(client, “opc.tcp://localhost:4840″); if(retval != UA_STATUSCODE_GOOD) { UA_Client_delete(client); return EXIT_FAILURE; } /* Read attribute */ UA_Int16 value = 0; while(reading){ signal(SIGINT, stopHandler); signal(SIGTERM, stopHandler); printf(”

Reading the value of node (1, \”modbus.data\”):

“); UA_Variant *val = UA_Variant_new(); retval = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, “modbus.data”), val); if(retval == UA_STATUSCODE_GOOD && UA_Variant_isScalar(val) && val->type == &UA_TYPES[UA_TYPES_INT16]) { value = *(UA_Int16*)val->data; printf(“the value is: %i

“, value); } UA_Variant_delete(val); sleep(1); } UA_Client_disconnect(client); UA_Client_delete(client); return EXIT_SUCCESS; }

4.2 Client程序分析

相对于Server来说,Client的代码就相对比较简单了。同样是先实例化一个Client并使用默认配置,配置好连接点之后就可以使用UA_Client_readValueAttribute函数读取数据了,在本程序中,我设置了一个循环结构,每一秒读取一次数据。当然OPC UA具有Pub/Sub功能,借助于Pub/Sub功能,我们能够以更具效率的方式获取数据,但此功能在本文中不再进行演示。下面编译Client程序并运行:

gcc client.c open62541.o -o client && ./client

运行效果如下:

5.使用虹科Eurotech网关读取OPC UA数据

上面已经展示了在虹科工业树莓派上运行OPC UA Server以及Client,可以正常运行并读取数据。下面,本文采用其他设备读取运行在虹科工业树莓派上的OPC UA Server的数据,看一下能不能正常运行。在本例中,采用的是虹科Eurotech边缘网关。关于虹科Eurotech边缘网关的详细信息,可以在我们的官网上https://www.hohuln.com/找到,此处不再详细介绍。

首先在ESF的web界面上进行如下配置(注意打开对应的防火墙端口):

然后就可以在Date板块得到获取的数据了。

6.小结

本文采用开源的open62541,在RevPi上部署了OPC UA Server及Client,完成了一个简单的协议转换程序(Modbus TCP转OPC UA),并使用虹科Eurotech网关对数据进行读取,均可正常工作。在实际应用中,您可以根据需要在虹科工业树莓派上灵活配置OPC UA,助您建立自己的IIoT网络。

详解树莓派控制蜂鸣器演奏乐曲

步进电机以及无源蜂鸣器这些都需要脉冲信号才能够驱动,这里将用GPIO的PWM接口驱动无源蜂鸣器弹奏乐曲,本文基于树莓派Mode B+,其他版本树莓派实现时需参照相关资料进行修改!

1 预备知识

1.1 无源蜂鸣器和有源蜂鸣器

无源蜂鸣器:内部没有震荡源,直流信号无法让它鸣叫。必须用去震荡的电流驱动它,2K-5KHZ的方波PWM (Pulse Width Modulation脉冲宽度调制)。5KHZ的电流方波就是每秒震动5K次,每一个完整的周期占用200us的时间,高点平占一部分时间,低电平占一部分时间。声音频率可控,可以做出不同的音效。

有源蜂鸣器:内部带震荡电路,一通电就鸣叫,所以可以跟前面LED一样,给个高电平就能响,编程比无源的更方便。

本文利用无源蜂鸣器弹奏乐曲,用的就是淘宝上普通的电磁式阻抗16欧交流/2KHz 3V 5V 12V通用无源蜂鸣器,如果手边没有无源蜂鸣器,用普通的耳机也可以来代替无源蜂鸣器。

1.2 PWM

PWM(Pulse Width Modulation)即脉冲宽度调制,是一种利用微处理器的数字输出来控制模拟电路的控制技术。可以用下面的一幅图来形象地说明PWM:

图中tpwm就是一个周期的时间长度。对于2KHz频率来说,那么周期就是1s/2K=500us。图中的D叫做占空比,指的是高电平的时间占用整个周期时间的百分比。第一个周期D=50%,那么就是高电平低电平的时间各占一半。接下来的D为33%,那就是通电时间为33%,剩余的不通电时间占用67%。树莓派Model B+有4个PIN脚支持PWM输出,如下图最右侧:

但是,需要注意的是BCM2835芯片只支持两路PWM输出,所以以上12 Pin脚和32 Pin脚对应的都是channel 1的PWM输出,即如果这两个Pin的功能都选择的是PWM输出,则它们输出的PWM是完全相同的,同理33 Pin脚和35 Pin脚对应芯片channel 2的PWM输出。

博通公司公布的BCM2835芯片资料BCM2835 ARM Peripherals中第9章比较详细的介绍了PWM相关内容,此外还可参考网上整理好的寄存器介绍资料rpi-registers,通过阅读可以得知树莓派Model B+支持两种模式的PWM输出:一种是Balanced mode(平衡模式),一种是Mark-Space mode(MS模式)。另外树莓派的PWM输出基础频率是19.2MHz,PWM输出频率受这个基础频率的限制。

1.3 树莓派PWM分析

进行分析前先看一下实验的物理电路连接:

图中,红色杜邦线一头连接树莓派的32 Pin脚(PWM0),一头连接示波器的探针;绿色杜邦线一头连接树莓派的12 Pin脚(PWM0),一头连接无源蜂鸣器的正极;黄色杜邦线一头连接树莓派的6 Pin脚(ground),一头连接无源蜂鸣器的负极,此外示波器探针的ground也连接到黄色杜邦线,结合bcm2835 C library来进行分析:

#下载bcm2835库 wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.50.tar.gz #解压 tar -zxvf bcm2835-1.50.tar.gz #进入目录 cd bcm2835-1.35 #编译 ./configure && make #安装 sudo make install

修改examples/pwm/pwm.c的内容如下:

// pwm.c // // Example program for bcm2835 library // Shows how to use PWM to control GPIO pins // // After installing bcm2835, you can build this // with something like: // gcc -o pwm pwm.c -l bcm2835 // sudo ./pwm // // Or you can test it before installing with: // gcc -o pwm -I ../../src ../../src/bcm2835.c pwm.c // sudo ./pwm // // Author: Mike McCauley // Copyright (C) 2013 Mike McCauley // $Id: RF22.h,v 1.21 2012/05/30 01:51:25 mikem Exp $ #include #include // PWM output on RPi Plug P1 pin 12 (which is GPIO pin 18) // in alt fun 5. // Note that this is the _only_ PWM pin available on the RPi IO headers #define PIN RPI_GPIO_P1_12 // and it is controlled by PWM channel 0 #define PWM_CHANNEL 0 // This controls the max range of the PWM signal #define RANGE 1024 #define PIN2 RPI_BPLUS_GPIO_J8_32 int main(int argc, char **argv) { if (!bcm2835_init()) return 1; // Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_ALT5); bcm2835_gpio_fsel(PIN2, BCM2835_GPIO_FSEL_ALT0); // 打开PI 32 Pin脚的PWM0输出功能 // Clock divider is set to 16. // With a divider of 16 and a RANGE of 1024, in MARKSPACE mode, // the pulse repetition frequency will be // 1.2MHz/1024 = 1171.875Hz, suitable for driving a DC motor with PWM bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_16); bcm2835_pwm_set_mode(PWM_CHANNEL, 0, 1); bcm2835_pwm_set_range(PWM_CHANNEL, RANGE); printf(“this is banlance mode, anykey will change to markspace mode

“); bcm2835_pwm_set_data(PWM_CHANNEL, RANGE/4); getchar(); printf(“change to markspace mode, anykey to exit

“); bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1); bcm2835_pwm_set_range(PWM_CHANNEL, RANGE); bcm2835_pwm_set_data(PWM_CHANNEL, RANGE/4); getchar(); bcm2835_close(); return 0; }

代码中首先设置PWM输出为平衡模式,之后按任意键切换为MS模式,编译:gcc -o pwm pwm.c -lbcm2835,运行:sudo ./pwm,示波器分别捕获到如下波形图:

代码第47行用divider=16对19.2MHz的基础频率进行调整,调整后的pwm频率为19.2MHz/16=1.2MHz,根据BCM2835芯片资料及代码49行和52行内容可知占空比应为N/M=(RANGE/4)/RANGE=256/1024,平衡模式力求任意一段时间占空比都最接近N/M=1/4,即把256个高电平时钟周期平均的分配到1024个之中周期中,可以这样进行处理,每4个时钟周期为一组,其中的一个周期内为高电平,这样即可实现“平衡”,这时真实的PWM输出帧率为1.2MHz/4=300KHz,如以上左图所示;对于MarkSpace模式来说,占空比为M/S=(RANGE/4)/RANGE=256/1024,这种模式不需要进行平衡,即可以认为1024个时钟周期的前256个为高电平,其余的为低电平,这时真实的PWM输出帧率为1.2MHz/1024=1171.875Hz,如以上右图所示。

2 树莓派播放音乐

2.1 乐理知识

一首乐曲有若干音符组成,每个音符由音调和演奏时间组成。不同的音调在物理上就对应不同频率的音波。所以我们只要控制输出的频率和时长就能输出一首音乐了。当然实际的音乐很复杂,又有连接,还有重音什么的,这个就先不在讨论范围内了。

每个音符都会播放一定的时间,这样就能构成一首歌曲。在音乐上,音符节奏分为1拍、1/2拍、1/4拍、1/8拍,假设一拍音符的时间为1;半拍为0.5;1/4拍为0.25;1/8拍为0.125……,所以我们可以为每个音符赋予这样的拍子播放出来,音乐就成了。

Arduino官方网站给出了不同音符对应的不同频率的头文件pitches.h,相关内容可以参考博文,在本文我们把pitches.h文件直接应用到树莓派,该文件内容如下:

/************************************************* * Public Constants *************************************************/ #define NOTE_B0 31 #define NOTE_C1 33 #define NOTE_CS1 35 #define NOTE_D1 37 #define NOTE_DS1 39 #define NOTE_E1 41 #define NOTE_F1 44 #define NOTE_FS1 46 #define NOTE_G1 49 #define NOTE_GS1 52 #define NOTE_A1 55 #define NOTE_AS1 58 #define NOTE_B1 62 #define NOTE_C2 65 #define NOTE_CS2 69 #define NOTE_D2 73 #define NOTE_DS2 78 #define NOTE_E2 82 #define NOTE_F2 87 #define NOTE_FS2 93 #define NOTE_G2 98 #define NOTE_GS2 104 #define NOTE_A2 110 #define NOTE_AS2 117 #define NOTE_B2 123 #define NOTE_C3 131 #define NOTE_CS3 139 #define NOTE_D3 147 #define NOTE_DS3 156 #define NOTE_E3 165 #define NOTE_F3 175 #define NOTE_FS3 185 #define NOTE_G3 196 #define NOTE_GS3 208 #define NOTE_A3 220 #define NOTE_AS3 233 #define NOTE_B3 247 #define NOTE_C4 262 #define NOTE_CS4 277 #define NOTE_D4 294 #define NOTE_DS4 311 #define NOTE_E4 330 #define NOTE_F4 349 #define NOTE_FS4 370 #define NOTE_G4 392 #define NOTE_GS4 415 #define NOTE_A4 440 #define NOTE_AS4 466 #define NOTE_B4 494 #define NOTE_C5 523 #define NOTE_CS5 554 #define NOTE_D5 587 #define NOTE_DS5 622 #define NOTE_E5 659 #define NOTE_F5 698 #define NOTE_FS5 740 #define NOTE_G5 784 #define NOTE_GS5 831 #define NOTE_A5 880 #define NOTE_AS5 932 #define NOTE_B5 988 #define NOTE_C6 1047 #define NOTE_CS6 1109 #define NOTE_D6 1175 #define NOTE_DS6 1245 #define NOTE_E6 1319 #define NOTE_F6 1397 #define NOTE_FS6 1480 #define NOTE_G6 1568 #define NOTE_GS6 1661 #define NOTE_A6 1760 #define NOTE_AS6 1865 #define NOTE_B6 1976 #define NOTE_C7 2093 #define NOTE_CS7 2217 #define NOTE_D7 2349 #define NOTE_DS7 2489 #define NOTE_E7 2637 #define NOTE_F7 2794 #define NOTE_FS7 2960 #define NOTE_G7 3136 #define NOTE_GS7 3322 #define NOTE_A7 3520 #define NOTE_AS7 3729 #define NOTE_B7 3951 #define NOTE_C8 4186 #define NOTE_CS8 4435 #define NOTE_D8 4699 #define NOTE_DS8 4978

可以看到,这是一张类似表格的东西,里面是定义的大量的宏,即用宏名代替了频率名,对应到键盘的各个按键上。我们需要对应相应的音符到宏名上,为了实现这个首先看看钢琴大谱表与钢琴琴键的对照表:

为了将个音符的音名直观的看出来,给出以下表格:

2.2 播放音乐

对照以上表格及射雕英雄传主题曲铁血丹心简谱实现树莓派播放,铁血丹心简谱如下:

上面的简谱中缺少前奏,程序中增加了从其他版本中摘录的前奏部分,主程序tiexuedanxin.c代码如下:

#include #include #include #include #include “pitches.h” #define PWM_CHANNEL 0 typedef struct _TONE{ int freq; int t_ms; } TONE,*PTONE; int pin = RPI_GPIO_P1_12; int baseFreq = 600000; // BCM2835_PWM_CLOCK_DIVIDER_32 对应600KHz typedef struct _melodyNode{ int note; float fDuration; }melodyNode; melodyNode melody[]= { // 1 {NOTE_A4, 1.5}, // 6 {NOTE_G4, 0.5}, // 5 {NOTE_A4, 1}, // 6 {NOTE_G4, 0.5}, // 5 {NOTE_E4, 0.5}, // 3 // 2 {NOTE_G4, 1}, // 5 {NOTE_D4, 3}, // 2 // 3 {NOTE_C4, 1.5}, // 1 {NOTE_A3, 0.5}, // .6 {NOTE_D4, 0.5}, // 2 {NOTE_E4, 0.5}, // 3 {NOTE_G4, 0.5}, // 5 {NOTE_F4, 0.5}, // 4 // 4 {NOTE_E4, 3}, // 3 {NOTE_E4, 0.5}, // 3 {NOTE_G4, 0.5}, // 5 // 5 {NOTE_A4, 1.5}, // 6 {NOTE_G4, 0.5}, // 5 {NOTE_A4, 1}, // 6 {NOTE_G4, 0.5}, // 5 {NOTE_E4, 0.5}, // 5 // 6 {NOTE_G4, 1}, // 5 {NOTE_D4, 3}, // 2 // 7 {NOTE_C4, 1.5}, // 1 {NOTE_A3, 0.5}, // .6 {NOTE_D4, 0.5}, // 2 {NOTE_E4, 0.5}, // 3 {NOTE_G3, 0.5}, // .5 {NOTE_B3, 0.5}, // .7 // 8 {NOTE_A3, 4}, // .6 {0, 1}, // 0 {NOTE_E4, 0.5}, // 3 {NOTE_D4, 0.5}, // 2 {NOTE_C4, 1.5}, // 1 {NOTE_B3, 0.5}, // .7 // {NOTE_A3, 1.5}, // .6 {NOTE_E3, 0.5}, // .3 {NOTE_A3, 2}, // .6 //{NOTE_A3, 1}, // .6 {NOTE_A4, 0.5}, // 6 {NOTE_G4, 0.5}, // 5 {NOTE_E4, 1}, // 3 {NOTE_G4, 0.5}, // 5 {NOTE_D4, 0.5}, // 2 {NOTE_E4, 3}, // 3 {NOTE_E4, 0.5}, // 3 {NOTE_D4, 0.5}, // 2 {NOTE_C4, 1.5}, // 1 {NOTE_B3, 0.5}, // .7 {NOTE_A3, 1.5}, // .6 {NOTE_E3, 0.5}, // .6 {NOTE_A3, 2}, // .6 {0, 1}, // 0 {NOTE_D4, 0.5}, // 2 {NOTE_C4, 0.5}, // 1 {NOTE_A3, 1}, // .6 {NOTE_C4, 0.5}, // 1 {NOTE_D4, 0.5}, // 1 {NOTE_E4, 3}, // 3*/ {NOTE_E4, 1}, // 3 逐草四方 {NOTE_A4, 1.5}, // 6 {NOTE_G4, 0.5}, // 5 {NOTE_A4, 1}, // 6 {NOTE_G4, 0.5}, // 5 {NOTE_E4, 0.5}, // 3 {NOTE_G4, 1}, // 5 {NOTE_D4, 3}, // 2 {NOTE_C4, 1.5}, // 1 {NOTE_A3, 0.5}, // .6 {NOTE_D4, 0.5}, // 2 {NOTE_E4, 0.5}, // 3 {NOTE_G4, 0.5}, // 5 {NOTE_FS4, 0.5}, // #4 {NOTE_E4, 3}, // 3 {NOTE_E4, 0.5}, // 3 {NOTE_G4, 0.5}, // 5 {NOTE_A4, 1.5}, // 6 {NOTE_G4, 0.5}, // 5 {NOTE_A4, 1.0}, // 6 {NOTE_G4, 0.5}, // 5 {NOTE_E4, 0.5}, // 3 {NOTE_G4, 1.0}, // 5 {NOTE_D4, 3}, // 2 {NOTE_C4, 1.5}, // 1 {NOTE_A3, 0.5}, // .6 {NOTE_D4, 0.5}, // 2 {NOTE_E4, 0.5}, // 3 {NOTE_G3, 0.5}, // .5 {NOTE_B3, 0.5}, // .7 {NOTE_A3, 3}, // .6 {0, 1}, // 0 {NOTE_E4, 0.5}, // 3 应知爱意似 {NOTE_D4, 0.5}, // 2 {NOTE_C4, 1.0}, // 1 {NOTE_C4, 0.5}, // 1 {NOTE_B3, 0.5}, // .7 {NOTE_A3, 1.5}, // .6 {NOTE_E3, 0.5}, // .3 {NOTE_A3, 2.0}, // .6 {0, 1}, // 0 {NOTE_A3, 0.5}, // .6 {NOTE_G3, 0.5}, // .5 {NOTE_E3, 1.0}, // .3 {NOTE_G3, 0.5}, // .5 {NOTE_D3, 0.5}, // .2 {NOTE_E3, 3.0}, // .3 {0, 1}, // 0 {NOTE_E4, 0.5}, // 3 身经百劫也 {NOTE_D4, 0.5}, // 2 {NOTE_C4, 1.0}, // 1 {NOTE_C4, 0.5}, // 1 {NOTE_B3, 0.5}, // .7 {NOTE_A3, 1.5}, // .6 {NOTE_E4, 0.5}, // 3 {NOTE_D4, 2.0}, // 2 {0, 1}, // 0 {NOTE_D4, 0.5}, // 2 {NOTE_C4, 0.5}, // 1 {NOTE_A3, 1.0}, // .6 {NOTE_B3, 0.5}, // .7 {NOTE_G3, 0.5}, // .5 {NOTE_A3, 3.0}, // .6 }; void beep(int freq, int t_ms) { int range; /*if(freq<2000||freq>5000) { printf(“invalid freq

“); return; }*/ if(freq == 0) range=1; else range=baseFreq/freq; printf(“will call bcm2835_pwm_set_range freq: %d range: %d

“, freq, range); bcm2835_pwm_set_range(PWM_CHANNEL, range); bcm2835_pwm_set_data(PWM_CHANNEL, range/2); if(t_ms>0) { delay(t_ms); } } void init() { if (!bcm2835_init()) exit (1) ; printf(“will init pin %d

“, pin); // Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_ALT5); bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_32); bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1); } int main (void) { int index=0; int nLen = sizeof(melody)/sizeof(melody[0]); init(); for ( ; index

用树莓派来实现钉钉打卡

来自 yoyolife 的投稿。

可以钉钉打卡的途径很多,我没研究过。公司是用wifi连接打卡的。所以我自己做了一个。懒得去研究其他方法,也不想花钱。

刚好有闲置的树莓派,和一台闲置的安卓手机。

我只要用 adb 调起钉钉,钉钉就会自动打卡了。那么就开干吧。

安装 adb

sudo apt-get update sudo apt-get install -y android-tools-adb android-tools-fastboot

把手机设为不用密码

然后运行下面基础代码

import time import threading import os,subprocess import base64 import random PATH = lambda p: os.path.abspath(p) isScreenshoting = False #打卡 def onWork(): # 开个线程截图 ts = threading.Thread(target=runLoopScreenshot, args=()) ts.setDaemon(True) global isScreenshoting isScreenshoting = True ts.start() os.system(‘adb shell input keyevent 26’) os.system(‘adb shell input keyevent 3’) os.system(‘adb shell am start -n com.alibaba.android.rimet/com.alibaba.android.rimet.biz.SplashActivity’) # 等15秒后关闭 time.sleep(15) os.system(‘adb shell input keyevent 3’) os.system(‘adb shell input keyevent 6’) isScreenshoting = False # 打卡完毕 tend = threading.Thread(target=enddk, args=()) tend.start() def enddk(): # 通知你想通知的地方 print(“end”) time.sleep(10) def runLoopScreenshot(): global isScreenshoting while isScreenshoting: # os.popen(“adb wait-for-device”) s = os.popen(“adb shell screencap -p | base64”).read() print(s) os.popen(“adb shell screencap -p /data/local/tmp/tmp.png”) path = ‘/home/pi’ os.popen(“adb pull /data/local/tmp/tmp.png ” + PATH(path + “/s.png”)) # os.popen(“adb shell rm /data/local/tmp/tmp.png”) # 图片转了base64 可以发到你想发的地方 with open(path + “/s.png”, “rb”) as f: base64_data = base64.b64encode(f.read()) print(‘success’) if __name__ == ‘__main__’: # 设置多几个打卡时间 dakaTime = [’08:49:40′, ’08:47:32′, ’08:53:25′] nextDakaTime = None while True: try: # 看有没有设备连接 device = os.popen(‘adb devices -l’).read() out = device.split(‘ ‘) print(‘{“action”:”device”,”data”:”%s,%s,%s”}’ % (out[11], out[12], out[13])) currentTime = time.strftime(“%H:%M:%S”, time.localtime()) if nextDakaTime == None: r = random.randint(0, len(dakaTime) – 1) nextDakaTime = dakaTime[r] print(currentTime,nextDakaTime) if currentTime == nextDakaTime: # 开个线程打卡 t = threading.Thread(target=onWork, args=()) t.setDaemon(True) t.start() except Exception as e: print(“something wrong:”, e) time.sleep(1)

上面的代码我修改了但没测试过

因为我之前是通过mqtt发到我的手机上

现在我把mqtt去了。自行修改代码发到邮件通知也行,用 wxpy 发到微信也行。

新年要到了,最后祝大家以后迟到不用扣钱。

来自 yoyolife 的投稿,出处:http://www.yoyolife.fun:9000/blog/post/5e0f00a29b8672003000015d