利用Pybind11封装Python版的WiringPi!

原版的WiringPi是一个用于树莓派的GPIO库,用C语言开发,仓库地址:https://github.com/WiringPi/WiringPi。该库允许用户以编程方式访问和控制树莓派的GPIO引脚。而随着Python在嵌入式设备上的快速发展,其对底层引脚的操作也变得越来越多,因此将WiringPi中的API接口封装出对应的Python接口显得格外重要了。

目前是有这个库的Python版本:https://github.com/WiringPi/WiringPi-Python,是利用swig这个工具自动读取头文件完成相关接口的封装,但该方式从使用角度来看存在以下几点问题:

  • 灵活性不够强。比如:某些函数返回值通过输入的指针来传递,这种swig就没法有效识别。
  • 未封装注释,且开发时无法弹出其中的API。开发时无法知道so文件内有什么函数,只能通过尝试去找相关用法。
  • 存在重定义问题。WiringPi是C语言,部分头文件存在重定义问题。

Python的最大优势就是降低开发者的使用难度,因此上述这个仓库并未良好的展示出这一特点。考虑到Pybind11是一款广为使用的封装工具,熟知的pytorch就是基于这个工具将其C++接口封装为python的。因此,我就借用Pybind11来提供一个超好用的Python版的WiringPi!!!!

🌈仓库地址:https://github.com/Li-Zhaoxi/Pybind11-WiringPi

下面将介绍怎么安装编译Python版的WiringPi,并介绍了使用方法,以及这段时间的开发历程。

💡💡特别感谢晟哥在使用体验上提供的宝贵建议😎😎

文章目录

  • 一 工具包编译
  • 二 使用方式
  • 三 开发过程
  • 四 小结

一 工具包编译

在编译前,有以下几点需要注意下:

  • 目前封装的WiringPi的仓库地址是https://gitee.com/study-dp/WiringPi,仅适用于地平线开发板。其他开发板比如树莓派等,我手上暂时没有,在后续开发中会慢慢补上,各位可以多多关注仓库主页以及Release信息。
  • Python包依赖C++库,编译时候会安装到系统环境中。在之后迭代时我打算将编译出的so文件都放在包这个路径下,而且编译过程全部自动化处理。

我说下封装的思想,Python包是在现有C++动态库的基础上进行的二次封装,这样在C++项目中和Python项目中只会启动一个so文件,起到节省内存的作用。

  • 如果你想从头编译本项目,编译安装流程如下:
# 安装依赖包
sudo pip3 install mypy ninja# 下载项目,recursive必须要加
git clone --recursive https://github.com/Li-Zhaoxi/Pybind11-WiringPi
cd Pybind11-WiringPi# 安装依赖的WiringPi C动态库
cd 3rdparty/WiringPi-RDK
./build
cd ../..# 安装Pybind11
cd 3rdparty/pybind11
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF ..
sudo make install
cd ../../..# 编译出用于安装的python.whl
python3 setup.py bdist_wheel# 安装我们编译好的包
sudo pip3 install dist/WiringPi*.whl
  • 如果你想利用我编译好的whl文件,可以从这里下载编译好的whl文件WiringPi-0.1.0-cp38-cp38-linux_aarch64.whl,之后编译安装流程如下:
# 下载项目,recursive必须要加
git clone --recursive https://github.com/Li-Zhaoxi/Pybind11-WiringPi
cd Pybind11-WiringPi# 安装依赖的WiringPi C动态库
cd 3rdparty/WiringPi-RDK
./build
cd ../..# 安装提供的python包,<path>表示包存放的根目录
sudo pip3 install <path>/WiringPi-0.1.0-cp38-cp38-linux_aarch64.whl

输入python3,如果能正确import WiringPi,就表明你已经正确安装当前项目,可以快乐开发了。

二 使用方式

先放使用效果图,在import WiringPi之后,你可以直接看到包内的所有函数接口以及相关的注释每个函数我都将C语言中的注释迁移过来了,而且我从使用角度对函数的api进行了微调!!!(还不快快谢谢小玺玺→_→)
在这里插入图片描述
我已经在项目主页的README中补充了包中所有的函数/变量的层级关系及接口声明。这样如果我们知道要调用的函数名,可以直接在项目主页中搜索这个函数名,得到调用方式。比如softPwmCreate这个函数的调用方式就是from WiringPi.softdriven import softPwmCreate
在这里插入图片描述

三 开发过程

这里我聊聊聊聊自己的开发细节,先说说为啥自己心血来潮要封装WiringPi,首先是因为去年Arui在利用X3的PWM接口时,官方提供的python版本的控制PWM出现抖动的问题,C++版本的wiringPi能满足要求,但没法python调用。当时快速给他用Cython包装了他要的接口,已经验证通过了。然而最近另一位开发者要使用这个东西,但是在他的板子上怎么也运行不起来,我又没太多时间教他怎么配置这个,为了减少各位在这种造轮子上花费的时间,所以我要将WiringPi这个库彻底封装。

该项目从1月10日创建,到目前出了一版,用了1个月的时间,在构造这个项目的时候,我就一直在思考构造一个“好用”的Package都要考虑什么,目前我想到的点主要有以下这些:

  • 接口设计。Python的习惯是利用返回值返回数据,而C语言是通过传递指针来输出数据的。我需要理解每个函数的用法,并制定相关的优化方式。
  • 安装简化。用最少的指令完成项目的编译与安装。即,利用pip install安装包,利用python setup.py生成包。
  • 注释完善/辅助开发。利用好vscode开发的自动弹出功能,展示函数的接口以及相关的注释,让内容变得透明。
  • 撰写好用的开发文档。从博客/项目readme等角度,减少用户的学习成本。

除了“接口设计”这一部分是开发部分的工作,其他的工作都是围绕着生态展开的,由此也可见生态是多么重要。封装WiringPi这个是个大工程,下面列举出我在开发时为了提升使用体验做出的努力😎:

  • 检查了所有函数的接口,并对其中一些函数的使用方式进行了优化。比如

    • 对于通过输入参数类型为指针来返回值的,通过lambda表达式进行了新的定义。函数void wiringPiVersion(int *major, int *minor)返回的版本信息,存储在major, minor中,这样我就可以将其封装为封装在返回值中,在py中可以通过major, minor = wiringPiVersion()的方式进行调用。
    • 优化了一些实际返回值是int但实际上应该是bool的函数。C语言中用1,0表示true,false,防止py使用时产生疑惑,我从其实现代码中将只返回0,1的函数返回类型改为bool。
    • 输入参数包含数组的函数,适配为输入np.ndarray的形式。比如函数void ds1302clockWrite(const int clockData[8]);需要输入一个包含8个元素的数组,对应的python声明为def ds1302clockWrite(clockData: numpy.ndarray[numpy.int32]) -> None,代码中会自动校验元素个数。
    • 按照传感器的类型进行了分类与整合。比如GPIO扩展芯片mcp23s08, pcf8574,我把相关的函数封装在WiringPi.gpio模块里。
  • 简化安装过程,编译这个包只需要python3 setup.py bdist_wheel即可

    • 在setup.py过程中就已经完成了辅助开发的构造。封装c++生成的so文件,vscode是无法弹出其中的函数的,也就意味着so文件对用户来说是不透明的。所以必须基于so文件生成对应的.pyi声明文件。
      • 最开始使用的是pybind11-stubgen,但是问题较多,C++17的特性支持的一般,研究测试了一段时间后放弃。
      • 目前使用的是mypy来导出大部分函数的声明与注释。但是奇怪的是每个模块的doc无法导出,只能在setup.py中补充个后处理函数来解决这个问题。
    • 在setup.py中利用cmakelists.txt对模块进行编译。就是将正常编译cmake项目关联的指令整理在一起,完成自动编译。当然由于包含模块的后处理之类的,这里对其中的一些关键函数进行了重载。
  • 整理了所有函数的注释。WiringPi中很多注释是写在.c文件里了,我把这些注释都封装在pybind中,量真的很大😭。

开发中我经常能遇到undefined symbol的问题,这里记录下导致这个问题的几种情况。
在这里插入图片描述

  • 头文件忘记extern "C"。比如报错说是_Z10rht03Setupii是个未定义的符号,
    • 首先利用c++filt _Z10rht03Setupii解析出函数声明:rht03Setup(int, int)
    • 然后nm -g /usr/local/lib/libwiringPi.so列举出这个库是否包含rht03Setup
    • 发现库包含这个函数,所以看头文件,发现没写extern "C"。这会导致C++项目链接到这个库时,无法引用相关的函数。补充上即可。
      在这里插入图片描述
  • Makefile漏掉了某些.c文件,比如softServo这个就没编译。同样,我利用nm工具发现库中就没这个函数,就直接去检查是否编译了。修复这个问题就能正常使用了。

四 小结

这一个月,下班回家后就开始研究封装相关的技术和工具,几乎天天从11点整理到2点,其实如果只是封装的话并不难,主要是很多传感器我要分类,我要研究用法。而且经常凌晨拉着晟哥哥讨论怎么设计结构,获取使用体验等等(真的感谢)。真心希望各位后续不会在接口的使用上困住。

WiringPi这个项目还有很多工作要做,在未来的工作中还需要继续完善与优化,还请各位多多关注仓库主页:Pybind11-WiringPi。后续的工作主要还是围绕以下几点:

  • 增加BPU推理python自定义层的支持。目前自定义层仅用于c++推理,导致部分模型,比如HED边缘检测算法,部署难度大幅增加。
  • 增加树莓派引脚的适配。我目前使用的WiringPi是地平线X3开发板专用的,为了避免对树莓派用户开发干扰,会补充个全局变量来解决。这部分工作其实就是解决设备兼容问题,欢迎树莓派用户一起来搞。
  • 尽可能补充各个模块函数的使用demo。降低用户的学习/开发成本。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2776664.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

学习通考试怎么搜题找答案? #学习方法#微信#其他

大学生必备的做题、搜题神器&#xff0c;收录上万本教材辅助书籍&#xff0c;像什么高数、物理、计算机、外语等都有&#xff0c;资源十分丰富。 1.菜鸟教程 菜鸟教程是一个完全免费的编程学习软件。 它免费提供了HTML / CSS 、JavaScript 、服务端、移动端、XML 教程、http…

leetcode(滑动窗口)483.找到字符中所有字母异位词(C++详细解释)DAY4

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符串&#xff08;包括相同的字符串&a…

通俗易懂:快速排序算法全解析

快速排序&#xff08;Quick Sort&#xff09;是一种高效的分治排序算法&#xff0c;它以其出色的性能和广泛的应用而闻名。本文将深入讲解快速排序的原理、步骤和时间复杂度&#xff0c;并探讨其优势和应用场景。 快速排序原理 快速排序的核心思想是通过选择一个基准元素&…

springboot167基于springboot的医院后台管理系统的设计与实现

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

Bee+SpringBoot稳定的Sharding、Mongodb ORM功能(同步 Maven)

Hibernate/MyBatis plus Sharding JDBC Jpa Spring data GraphQL App ORM (Android, 鸿蒙) Bee 小巧玲珑&#xff01;仅 860K, 还不到 1M, 但却是功能强大&#xff01; V2.2 (2024春节・LTS 版) 1.Javabean 实体支持继承 (配置 bee.osql.openEntityCanExtendtrue) 2. 增强批…

Vue源码系列讲解——虚拟DOM篇【三】(更新子节点)

1. 前言 在上一篇文章中&#xff0c;我们了解了Vue中的patch过程&#xff0c;即DOM-Diff算法。并且知道了在patch过程中基本会干三件事&#xff0c;分别是&#xff1a;创建节点&#xff0c;删除节点和更新节点。创建节点和删除节点都比较简单&#xff0c;而更新节点因为要处理…

“掌握温度,感知湿度,一触即知!”DHT11温湿度传感器,为您的生活增添一份关怀与精准。#非标协议【下】

“掌握温度&#xff0c;感知湿度&#xff0c;一触即知&#xff01;”DHT11温湿度传感器&#xff0c;为您的生活增添一份关怀与精准。#非标协议【下】 前言预备知识1.DHT11温湿度传感器初识1.1产品概述1.2与51单片机接线1.3数据传送逻辑和数据格式 2.发送时序检测DHT11温湿度传感…

npm 上传一个自己的应用(3) 在项目中导入及使用自己上传到NPM的工具

上文 npm 上传一个自己的应用(2) 创建一个JavaScript函数 并发布到NPM 我们创建了一个函数 并发上了npm 最后 我们这里 我们可以看到它的安装指令 这里 我们可以打开一个vue项目 终端输入 我们的安装指令 npm i 自己的包 如下代码 npm i grtest我们在 node_modules目录 下…

[C#]winform制作仪表盘好用的表盘控件和使用方法

【仪表盘一般创建流程】 在C#中制作仪表盘文案&#xff08;通常指仪表盘上的文本、数字或指标显示&#xff09;涉及到使用图形用户界面&#xff08;GUI&#xff09;组件&#xff0c;比如Windows Forms、WPF (Windows Presentation Foundation) 或 ASP.NET 等。以下是一个使用W…

Linux网络通信——TCP/OSI七层模型/TCP/IP(五层或四层模型)/HTTP报文传输原理

文章目录 消息的传输什么是OSI七层模型OSI七层模型的内容物理层&#xff08;Physical Layer&#xff09;&#xff1a;数据链路层&#xff08;Data Link Layer&#xff09;&#xff1a;网络层&#xff08;Network Layer&#xff09;&#xff1a;传输层&#xff08;Transport Lay…

vue3-内置组件-Teleport

Teleport <Teleport> 是一个内置组件&#xff0c;它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。 基本用法 有时我们可能会遇到这样的场景&#xff1a;一个组件模板的一部分在逻辑上从属于该组件&#xff0c;但从整个应用视图的角度来看…

实现注册登录时数据的加密传输(含前后端具体代码)

前言 http/https协议提交在被抓包时请求内容是明文的, 直接传输账号密码的风险非常大&#xff0c;故这里我们要对数据加密处理&#xff0c;并生成校验码&#xff0c;防止数据篡改 目录 ​编辑 前言 具体思路 代码实现 前端信息加密处理&#xff08;Vue&#xff09; 安装…

Java多线程:线程安全

&#x1f451;专栏内容&#xff1a;Java⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、线程状态1、New&#xff08;初始状态&#xff09;2、Terminated&#xff08;终止状态&#xff09;3、Runnable&#xff08;…

C++类型转化cast from pointer to smaller type ‘int‘ loses information

代码如下 #include <iostream>int main() {int a 10;std::cout << (int)&a << std::endl;return 0; }编译 这段代码是要将地址转化成整数类型&#xff0c;但是在编译时编译器告诉我们这是错的&#xff0c;因为在C中&#xff0c;将指针转换为int类型的…

Spring基础 - Spring核心之面向切面编程(AOP)

Spring基础 - Spring核心之面向切面编程(AOP) 引入 Spring 框架通过定义切面, 通过拦截切点实现了不同业务模块的解耦&#xff0c;这个就叫面向切面编程 - Aspect Oriented Programming (AOP)那么Spring框架又是如何实现AOP的呢&#xff1f; 这就引入代理技术&#xff0c;分静…

Sqlite3安装步骤

1、Sqlite3以下载文件&#xff0c;配置环境变量的方式进行安装。 2、下方链接为官方的下载地址。 sqlite下载地址 2.1、需要两个下载文件&#xff0c;解压后将他们放在一起&#xff0c;假设解压后的路径为E:\sqlite。 sqlite-dll-win-x64-3450100.zip sqlite-tools-win-x6…

C++自定义函数详解

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 铁汁们新年好呀&#xff0c;今天我们来了解自定义函数。 文章目录 1.数学中的函数 2.什么是自定义函数 3.自定义函数如何使用&#xff1f; 4.值传递和引用传递&#xff08;形参和实参区分&#xff09; …

OLED调试简介

文章目录 一、介绍调试方法介绍OLED简介硬件电路OLED驱动函数 二、操作连接线路使用驱动函数显示内容 OLED.c的内容 一、介绍 调试方法介绍 OLED简介 硬件电路 OLED驱动函数 二、操作 连接线路 因为这两个引脚不做配置是浮空状态&#xff0c;在这里直接用电源给OLED供电 使…

嵌入式学习之Linux入门篇笔记——10,Linux连接档概念

配套视频学习链接&#xff1a;http://【【北京迅为】嵌入式学习之Linux入门篇】 https://www.bilibili.com/video/BV1M7411m7wT/?p4&share_sourcecopy_web&vd_sourcea0ef2c4953d33a9260910aaea45eaec8 目录 1.Linux 下的连接档种类 2.什么是 inode&#xff1f; 3.什…

Node.js JSON Schema Ajv依赖库逐步介绍验证类型和中文错误提示

在构建应用程序时&#xff0c;数据的有效性是至关重要的。为了确保传入的数据符合预期的格式和规范&#xff0c;我们可以使用 Ajv&#xff08;Another JSON Schema Validator&#xff09;进行验证。在这篇博文中&#xff0c;我们将从头开始学习 Ajv&#xff0c;逐步介绍验证类型…