树莓派中通过 wifi 的 Python 套接字

Mee*_*sai 3 python sockets networking tcp raspberry-pi

我用 python 编写了一个套接字。基本上有 2 个树莓派相互通信并使用套接字通过 wifi 发送 GPIO 数据。该代码有时工作得很好,但有时它要么不起作用,要么显示出很多滞后。可能出现什么问题。我是不是错过了什么。我是网络和 python 新手。请帮我!!

服务器代码是

#!/usr/bin/python
import RPi.GPIO as GPIO
import socket
HOST='192.168.0.106'
PORT=5002
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr=s.accept()
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
print 'Connected by', addr
GPIO.setmode(GPIO.BCM)
GPIO.setup(04, GPIO.IN)
GPIO.setup(17, GPIO.IN)
GPIO.setup(27, GPIO.IN)
while True:
    if (GPIO.input(04)==True):
        if (GPIO.input(17)==False):
                if (GPIO.input(27)==False):
                        conn.send('0')
                elif(GPIO.input(27)==True):
                        conn.send('1')
        elif (GPIO.input(17)==True):
                if (GPIO.input(27)==False):
                        conn.send('2')
                elif (GPIO.input(27)==True):
                        conn.send('3')
    elif (GPIO.input(04)==False):
        conn.send('5')
s.close()
Run Code Online (Sandbox Code Playgroud)

客户端代码在这里

#!/usr/bin/python
import socket
import RPi.GPIO as GPIO
HOST='192.168.0.106'
PORT=5002
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
GPIO.setmode(GPIO.BCM)
GPIO.setup(02, GPIO.OUT)
GPIO.setup(03, GPIO.OUT)
GPIO.setup(11, GPIO.OUT)
GPIO.setup(10, GPIO.OUT)
while 1:
    data=s.recv(8096)
    if data=='0':
            print 'Forward'
            GPIO.output(02,True)
            GPIO.output(03, False)
            GPIO.output(11, False)
    elif data=='1':
            print 'Backward'
            GPIO.output(02, False)
            GPIO.output(03, True)
            GPIO.output(11, True)
            GPIO.output(10, False)
    elif data=='2':
            print 'Left'
            GPIO.output(02, False)
            GPIO.output(03, False)
            GPIO.output(11, False)
            GPIO.output(10, True)
    elif data=='3':
            print 'Right'
            GPIO.output(02, True)
            GPIO.output(03, False)
            GPIO.output(11, False)
            GPIO.output(10, False)
    elif data=='5':
            print 'Stop'
            GPIO.output(02, False)
            GPIO.output(03, False)
            GPIO.output(11, False)
            GPIO.output(10, False)
s.close()
Run Code Online (Sandbox Code Playgroud)

Jea*_*one 5

您的代码中有一些不符合习惯的地方。还有一些事情可能会影响其行为。

if (GPIO.input(04)==True):
Run Code Online (Sandbox Code Playgroud)

你应该这样写这个语句:

if GPIO.input(4):
Run Code Online (Sandbox Code Playgroud)

我删除的括号完全是多余的。它们没有什么区别。

我也改为04因为404八进制文字。对于这个特定值没有区别,因为八进制 4 和十进制 4 是相同的值。不过,在这里使用八进制是令人困惑和令人惊讶的(如果使用八进制来引用 GPIO 引脚是惯用的,那么这可能是这里使用八进制的原因,但据我所知并非如此)。由于您的引脚编号恰好为 8 或更大,因此这里没有使用八进制表示法编写,我猜这是无意的。

我还删除了与 的显式比较True。你几乎不应该与 进行比较TrueGPIO.input(4) == True计算结果为TrueifGPIO.input(4)返回True。所以你不妨跳过额外的比较(或者从另一个角度来看,你为什么不写if (GPIO.input(4) == True) == True:?)。

类似于这样的行:

if (GPIO.input(27)==False):
Run Code Online (Sandbox Code Playgroud)

你应该这样写:

if not GPIO.input(27):
Run Code Online (Sandbox Code Playgroud)

你几乎不应该与False任何一个进行比较。

也许更严肃地说:

if (GPIO.input(27)==False):
    conn.send('0')
elif(GPIO.input(27)==True):
    conn.send('1')
Run Code Online (Sandbox Code Playgroud)

我认为在程序中此时对该引脚进行两次采样对于您的应用程序来说并不重要 - 但这就是您正在做的事情。很可能第一个调用GPIO.input(27)将返回True,第二个调用也将返回False。在这种情况下,你的程序不会采取任何行动——谁知道后果是什么。

相反,你应该写一些类似的东西:

if GPIO.input(27):
    conn.send('1')
else:
    conn.send('0')
Run Code Online (Sandbox Code Playgroud)

也许最重要的是

while 1:
    data=s.recv(8096)
    if data=='0':
Run Code Online (Sandbox Code Playgroud)

这是对套接字 API 的误用。您要求最多 8096 个字节,然后您处理结果就像您要求最多 1 个字节一样。伴随程序每次总是写入 1 个字节并不重要。TCP 允许将这些写入合并在一起。

相反,你应该写:

while 1:
    data = s.recv(1)
    if data=='0':
Run Code Online (Sandbox Code Playgroud)

嗯,这并不是真正理想的编写方式,但这是使代码按照您的意图进行的最小更改。

目前尚不清楚这是否与您遇到的问题有关,但由于缺乏特定的硬件,我怀疑任何人都可以真正重现该问题。

使用代码修复这些问题后,下一个调试步骤应该是缩小延迟首次出现的位置。

也许发送端的 GPIO 引脚受到干扰,数据停止从其中输出。也许 GPIO 库中的某些内容在某些输入集下表现不正常。也许其中一个树莓派上的网络堆栈存在问题 - 由于资源限制或硬件故障或其他我无法猜测的原因 - 等等。

因此,对发送方进行检测,以便您可以判断它是否定期发送数据,或者是否存在延迟。如果它定期发送数据,则对接收器进行检测以查看其是否定期接收数据。如果是,那么您可能会将问题范围缩小到接收端的 GPIO 库或引脚。

仪器可以非常简单。例如,尝试time.time()在循环内部添加一些打印和调用。这将使您看到循环体运行的频率。如果您注意到时间间隔,那么您就得到了第一个线索。