Qt调用Python脚本读取JetsonNano开发板GPIO电平信号

一、简介

1.实现功能

能够实时读取JetsonNano开发板GPIO口的电平信号,并将读到的电平信号返回到Qt主程序中

2.环境工具

开发板:JetsonNano
系统:Ubuntu
语言:C/C++,python

二、准备工作

1.JetsonNano开发板GPIO口介绍

GPIO.png

JetsonNano的引脚与树莓派相似,有两种定义模式,一种是BCM编码,对应的是GPIO功能编码(图中Sysfs GPIO),一种是物理引脚编码,即BOARD编码(图中Pin)。

2.查看开发板是否预装了GPIO口的运行环境

1
cd /opt/nvidia/jetson-gpio

一般默认是安装好的,如果没有安装好,依次执行一下命令

1
2
3
4
安装pip工具
 sudo apt-get update
 sudo apt-get install python-pip
 sudo apt-get install python3-pip
1
2
3
下载安装Jetson.GPIO库:
sudo pip install Jetson.GPIO
sudo pip3 install Jetson.GPIO

1
2
3
4
5
6
7
8
9
10
设置用户权限:
sudo groupadd -f -r gpio
sudo usermod -a -G gpio your_user_name

注意:这里的your_user_name需要改成你自己的账号名,不然库无法正常使用

将99-gpio.rules文件复制到rules.d目录
sudo cp lib/python/Jetson/GPIO/99-gpio.rules /etc/udev/rules.d/
重载rules规则来让文件生效
sudo udevadm control --reload-rules && sudo udevadm trigger

以上方法参照https://www.waveshare.net/study/portal.php?mod=view&aid=882这篇文章,我自己并没有实际操作过,因为我得板子里已经是预装好了的

3查看一些官方示例

官方给出了一些关于GPIO口的输入输出PWM控制等的简单例子,进入文件夹可查看

1
cd /opt/nvidia/jetson-gpio/samples/

三、使用Qt调用Python

1.将Python的include和lib添加到Qt工程的.pro文件中

找到Python的安装路径,在Qt的.pro文件中添加include和lib,如图在.pro的最后添加即可,我这里为了不出错,把两个版本的python库都加进来了,其实加3.6应该就可以,加进去之后记得Ctrl+S保存一下,或者直接编译一下


.pro文件.png

2.在qt中加入头文件#include

如果第一步没问题的话,#include会自动补齐

3.根据自己的需要编写python脚本

我这里要实现的功能是实时读取35,36,37,38四个GPIO口的电平状态,返回0或者1到主程序中,当35,36,38电平为高的时候,主程序的四个监控画面对应其中一个全屏显示;37脚外接控制台,长时间拉高,当控制台电源按钮关闭时,控制台会掩饰30s关闭,但是会将Pin37拉低,如果Pin37为低电平,开发板关机。python脚本程序如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/usr/bin/env python

import RPi.GPIO as GPIO
import time

#这里我用BOARD编码的方式定义引脚
input_pin = 37  
left_pin = 35
right_pin = 36
back_pin = 38

def sleep_time(hour,min,sec):
        return hour *3600 + min * 60 +sec

def left():
    GPIO.setmode(GPIO.BOARD)#设置引脚为BOARD编码
    try:
        while True:
            GPIO.setup(left_pin,GPIO.IN)#设置引脚为输入
            value2 = GPIO.input(left_pin)#将该引脚的电平状态赋予value2
            return value2#返回value2,在qt中调用时所需要用到的值
            time.sleep(5)
    finally:
        GPIO.cleanup()#使用完后将引脚状态清零初始化
#下面的每个函数对应一个引脚,写法大同小异
def right():
    GPIO.setmode(GPIO.BOARD)
    try:
        while True:
            GPIO.setup(right_pin,GPIO.IN)
            value3 = GPIO.input(right_pin)
            return value3
            time.sleep(5)
    finally:
        GPIO.cleanup()

def back():
    GPIO.setmode(GPIO.BOARD)
    try:
        while True:
            GPIO.setup(back_pin,GPIO.IN)
            value4 = GPIO.input(back_pin)
            return value4
            time.sleep(5)
    finally:
        GPIO.cleanup()

def main():
    prev_value = None
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(input_pin, GPIO.IN)
    try:
        while True:
            value1 = GPIO.input(input_pin)
            return value1
            time.sleep(5)
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()

这里返回的value值,只有0和1,不会有电压大小

4.编写Qt程序

调用方法如下面的代码,头文件等忽略,只展示程序主体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
void MainWindow::GpioRead
{
    while(true)
    {
        Py_Initialize();//初始化
        if(!Py_IsInitialized())
        {
            qDebug()<<"python init fail";
        }
        else
        {
            qDebug()<<"python init sucess";
        }
        //导入python需要使用的头文件
        PyRun_SimpleString("import sys");
        PyRun_SimpleString("sys.path.append('./')");
        //将需要调用的python脚本打开,simple_input.py,不要写.py,写文件名即可
        PyObject *pModule = PyImport_ImportModule("simple_input");
        if(!pModule)
        {
            qDebug()<<"can not open file";
        }
        else
        {
            qDebug()<<"open python file sucess";
        }
        //调用打开的python脚本中的函数,这里调用的是main函数
        PyObject *pFun = new PyObject;
        pFun = PyObject_GetAttrString(pModule,"main");
        if(!pFun)
        {
            qDebug()<<"get fun fail";
        }
        else
        {
            qDebug()<<"get fun sucess";
        }

        PyObject *pCallBack = new PyObject;
        pCallBack = PyObject_CallFunction(pFun,NULL);
        //将调用main函数所得的返回值以int类型返回赋予pyResult
        int pyResult = 0;
        PyArg_Parse(pCallBack,"i",&pyResult);
        //如果返回值为0,即引脚电平为0,执行关机命令
        if(pyResult == 0)
        {
            system("halt -p");
        }
        //调用left函数,返回值赋予pyResultl
        PyObject *pleft = new PyObject;
        pleft = PyObject_GetAttrString(pModule,"left");
        PyObject *pCallBackl = new PyObject;
        pCallBackl = PyObject_CallFunction(pleft,NULL);
        PyArg_Parse(pCallBackl,"i",&pyResultl);
        qDebug()<<"pyResultl = "<<pyResultl;
        //调用right函数,返回值赋予pyResultr
        PyObject *pright = new PyObject;
        pright = PyObject_GetAttrString(pModule,"right");
        PyObject *pCallBackr = new PyObject;
        pCallBackr = PyObject_CallFunction(pright,NULL);
        PyArg_Parse(pCallBackr,"i",&pyResultr);
        qDebug()<<"pyResultr = "<<pyResultr;
        //调用back函数,返回值赋予pyResultb
        PyObject *pback = new PyObject;
        pback = PyObject_GetAttrString(pModule,"back");
        PyObject *pCallBackb = new PyObject;
        pCallBackb = PyObject_CallFunction(pback,NULL);
        PyArg_Parse(pCallBackb,"i",&pyResultb);
        qDebug()<<"pyResultb = "<<pyResultb;
        //调用函数gpioFullBack,传入参数,当返回值为1时,对应的监控画面全屏,该函数后续贴出
        gpioFullBack(pyResultl,pyResultr,pyResultb);
        Py_Finalize();//关闭python文件
        sleep(5);//延时5s
     }
}

5.将Qt程序进行编译

编译Qt程序,先不要运行,编译通过后,将写好的python脚本文件放在编译的文件夹下。然后运行程序,亲测基本是没有问题的

四、补充

1、gpioFullBack函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//一共有四个画面,对应前后左右,当倒车时,左转时,右转时,都有对应的画面全屏显示
void MainWindow::gpioFullBack(int pyResultFull,int pyResultFulll,int pyResultFullr)
{
    int height = this->geometry().height() - this->ui->toolBar->height();
    if(pyResultFull == 1)
    {
            QRect draw_rect(this->geometry().x(), this->geometry().y(), this->geometry().width(), height);
            ui->label_show_second_camera->resize(draw_rect.width(), draw_rect.height());
            ui->label_show_second_camera->move(draw_rect.x(), draw_rect.y());
            ui->label_show_first_caemra->hide();
            ui->label_show_third_camera->hide();
            ui->label_show_fourth_camera->hide();
    }
    else if(pyResultFulll == 1)
    {

        QRect draw_rect(this->geometry().x(), this->geometry().y(), this->geometry().width(), height);
        ui->label_show_third_camera->resize(draw_rect.width(), draw_rect.height());
        ui->label_show_third_camera->move(draw_rect.x(), draw_rect.y());
        ui->label_show_first_caemra->hide();
        ui->label_show_second_camera->hide();
        ui->label_show_fourth_camera->hide();
    }
    else if(pyResultFullr == 1)
    {
        QRect draw_rect(this->geometry().x(), this->geometry().y(), this->geometry().width(), height);
        ui->label_show_fourth_camera->resize(draw_rect.width(), draw_rect.height());
        ui->label_show_fourth_camera->move(draw_rect.x(), draw_rect.y());
        ui->label_show_first_caemra->hide();
        ui->label_show_second_camera->hide();
        ui->label_show_third_camera->hide();
    }
    else
    {
        adjustItem(use_camera_);
    }
}

2.过程中遇到的问题

略,后续补充