树莓派上通过WiFi使用Python套接字
我用Python编写了一个套接字程序。基本上有两个树莓派,它们通过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()
客户端的代码在这里
#!/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()
1 个回答
你的代码有些地方不太符合常规写法,还有一些可能会影响它的运行效果。
if (GPIO.input(04)==True):
你应该把这段代码改成这样:
if GPIO.input(4):
我去掉的括号是多余的,没什么用。
我还把 04
改成了 4
,因为 04
是八进制数字。对于这个值来说,八进制的4和十进制的4是一样的。不过在这里用八进制会让人感到困惑和意外(如果习惯上用八进制来表示GPIO引脚,那可能会有理由使用八进制,但据我所知并不是这样)。因为你的引脚号如果是8或更大的数字在这里没有用八进制表示,所以我猜这不是故意的。
我还去掉了对 True
的明确比较。你几乎不应该和 True
进行比较。GPIO.input(4) == True
如果 GPIO.input(4)
返回 True
,那么这个表达式就会是 True
。所以你可以省略这个多余的比较(换个角度想,为什么不写成 if (GPIO.input(4) == True) == True:
呢?)。
类似的,对于这样的代码:
if (GPIO.input(27)==False):
你应该改成这样:
if not GPIO.input(27):
你几乎也不应该和 False
进行比较。
可能更严重的是:
if (GPIO.input(27)==False):
conn.send('0')
elif(GPIO.input(27)==True):
conn.send('1')
我觉得在你程序的这个阶段,重复读取这个引脚两次并不是很关键,但你确实是这么做的。很有可能第一次 GPIO.input(27)
返回 True
,而第二次返回 False
。在这种情况下,你的程序不会执行任何操作,后果谁知道呢。
你应该写成类似这样的:
if GPIO.input(27):
conn.send('1')
else:
conn.send('0')
而且也许最重要的是
while 1:
data=s.recv(8096)
if data=='0':
这是对socket API的错误使用。你请求了最多8096字节,但却把结果当成最多1字节来处理。即使伴随程序每次只写1字节也没关系。TCP是允许把这些写操作合并在一起的。
你应该改成:
while 1:
data = s.recv(1)
if data=='0':
嗯,这并不是最理想的写法,但这是让代码按你想要的方式运行的最小改动。
这些问题是否和你遇到的麻烦有关还不太清楚,但没有你的具体硬件,我怀疑没人能真正复现这个问题。
在修复了这些代码问题后,你的下一个调试步骤应该是找出延迟最早出现的地方。
可能是发送端的GPIO引脚受到干扰,导致数据停止输出。也可能是GPIO库在某些输入下表现不正常。或者是某个树莓派的网络栈出现问题——可能是资源不足、硬件故障或其他我无法猜测的原因等等。
所以要对发送端进行监测,看看它是否在定期发送数据,或者延迟是否是在这里引入的。如果它在定期发送数据,那就对接收端进行监测,看看它是否在定期接收数据。如果是这样,那也许你就把问题缩小到GPIO库或接收端的引脚上了。
监测可以非常简单。例如,可以在循环中加几个打印语句和调用 time.time()
。这样你就能看到循环体运行的频率。如果你发现时间上有间隔,那就是你的第一个线索。