gpt4 book ai didi

python - 如果您不知道有多少数据通过,如何接收套接字信息?

转载 作者:太空宇宙 更新时间:2023-11-03 14:33:35 24 4
gpt4 key购买 nike

我正在开发基于 Python 的 GUI 界面,以与运行 Python 的机器人和 Arduino Mega 进行交互作为电机 Controller 和传感器 Controller 。

最初,我打算使用远程桌面从机器人加载我的 GUI。由于远程桌面,结果证明这非常慢。我决定服务器和客户端会更好。

我有一个 sketch在我的 Arduino 上运行,捕捉电机命令并执行它们。它还等待“Ping”命令通过,此时它应该检查三个不同位置的超声波传感器,然后将此信息写回服务器,服务器应捕获此数据并将其传递给客户端图形用户界面。我已经完成了大部分工作,但我似乎无法将数据从服务器返回到客户端。我原以为一个简单的“client.recv()”就可以做到这一点,但事实并非如此。

如果我不知道到底有多少数据返回,我如何接收该数据?

Arduino 将数据发送为“dist1,dist2,dist3\n”。

这是我的 Arduino 代码:

#include <LiquidCrystal.h>
#include <Ping.h>
#include <Servo.h>
// Parallax Ping Unit for distance sensing.
Ping sonic(22);

// Setup LCD pins.
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

// Servo for Ping unit sweeping.
Servo PingServo;

// Setup Ping distance setting variables.
int pingDisCent;
int pingDisLeft;
int pingDisRight;

// Variable to keep commands in.
char MsgRcvd;

// Motor setup information.

int LF[] = {23,24};
int LR[] = {25,26};
int RF[] = {27,28};
int RR[] = {29,30};

// Set Debugging here
// 1 - Debug on - Motors don't turn when commands are sent.
// 0 - Debug off - Motors turn when commands are sent.
int debug = 1;

//Variables for speed
int SpdPin = 22;
int Speed = 255;

void setup()
{
Serial.begin(9600); // start serial communications

// Setup motors for output.
int i;
for(i = 0; i < 2; i++){
pinMode(LF[i], OUTPUT);
pinMode(LR[i], OUTPUT);
pinMode(RF[i], OUTPUT);
pinMode(RR[i], OUTPUT);
}

// Setup servo to sweep.
PingServo.attach(6);
PingServo.write(90);

// Set up the LCD's number of rows and columns:
lcd.begin(16, 2);

// Print a message to the LCD.
lcd.print("Waiting...");

// Setup speed pin.
pinMode(SpdPin, OUTPUT);
}

void loop()
{
if (Serial.available() > 0) //Check to see if a command is available.
{
MsgRcvd = Serial.read(); // If a command is there, see what it is.
switch (MsgRcvd)
{
case '0':
Stop();
break;
case '1':
MoveForward();
break;
case '2':
MoveLeft();
break;
case '3':
MoveRight();
break;
case '4':
MoveBackward();
break;
case '~':
active_ir();
break;
case 'M': // Check to see if we have a connection from the GUI - if so spit out information to the LCD.
lcd.clear();
lcd.print("Connected");
lcd.setCursor(0,1);
lcd.print("waiting..");
break;
case 'D':
lcd.setCursor(0,1);
lcd.print("Disconnected"); // Client disconnected - spit out a disconnect to the LCD.
break;
}
}
delay(100);
}

// ===================================
// ===== Ping Ultrasonic =====
// ===================================
void active_ir()
{
// Read to the right.
PingServo.write(30);
delay(300);
pingDisRight = sonic.inch();
delay(500);

// Read to the front.
PingServo.write(90);
delay(300);
pingDisCent = sonic.inch();
delay(500);
// Read to the left.
PingServo.write(150);
delay(300);
pingDisLeft = sonic.inch();
delay(500);
Serial.print(pingDisLeft);
Serial.print(',');
Serial.print(pingDisCent);
Serial.print(',');
Serial.println(pingDisRight);
return;
}



// ==========================================
// ====== MOTOR CONTROL =========
// ==========================================

void MoveForward()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Forward");
if (debug == 0){

digitalWrite(LF[0], HIGH);
digitalWrite(LF[1], LOW);
digitalWrite(LR[0], HIGH);
digitalWrite(LR[1], LOW);
digitalWrite(RF[0], HIGH);
digitalWrite(RF[1], LOW);
digitalWrite(RR[0], HIGH);
digitalWrite(RR[1], LOW);
}
}

void MoveBackward()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Reverse");
if (debug == 0){
analogWrite(SpdPin, Speed);
digitalWrite(LF[0], LOW);
digitalWrite(LF[1], HIGH);
digitalWrite(LR[0], LOW);
digitalWrite(LR[1], HIGH);
digitalWrite(RF[0], LOW);
digitalWrite(RF[1], HIGH);
digitalWrite(RR[0], LOW);
digitalWrite(RR[1], HIGH);
}
}

void MoveLeft()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Left");
if (debug == 0){
analogWrite(SpdPin, Speed);
digitalWrite(LF[0], LOW);
digitalWrite(LF[1], HIGH);
digitalWrite(LR[0], LOW);
digitalWrite(LR[1], HIGH);
digitalWrite(RF[0], HIGH);
digitalWrite(RF[1], LOW);
digitalWrite(RR[0], HIGH);
digitalWrite(RR[1], LOW);
}
}

void MoveRight()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Right");
if (debug == 0) {
analogWrite(SpdPin, Speed);
digitalWrite(LF[0], HIGH);
digitalWrite(LF[1], LOW);
digitalWrite(LR[0], HIGH);
digitalWrite(LR[1], LOW);
digitalWrite(RF[0], LOW);
digitalWrite(RF[1], HIGH);
digitalWrite(RR[0], LOW);
digitalWrite(RR[1], HIGH);
}
}

void Stop()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Stopping");
if (debug == 0){
digitalWrite(LF[0], LOW);
digitalWrite(LF[1], LOW);
digitalWrite(LR[0], LOW);
digitalWrite(LR[1], LOW);
digitalWrite(RF[0], LOW);
digitalWrite(RF[1], LOW);
digitalWrite(RR[0], LOW);
digitalWrite(RR[1], LOW);
}
}

这是我的 Python 服务器代码:

import serial
import socket

Serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Serv.bind(('', 9000))
Serv.listen(1)
print "Listening on TCP 9000"
motor = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
print "Connected to Motor Controller: /dev/ttyUSB0"

while(1):
print "Waiting For Connection..."
connection, addr = Serv.accept()
connection.setblocking(0)
print "Connected by", addr[0]
while(1):
try:
Servdata = connection.recv(1)
break
except:
pass
if (Servdata == 'M'):
print "Entering Manual Mode"
motor.write(Servdata)
while(Servdata != 'X'):
Servdata = '9'
try:
Servdata = connection.recv(1)
except:
pass
if Servdata == 'X':
print "Exiting"
break
if Servdata == '0':
print "Stopping"
motor.write(Servdata)
if Servdata == '1':
print "Forward"
motor.write(Servdata)
if Servdata == '2':
print "Left"
motor.write(Servdata)
if Servdata == '3':
print "Right"
motor.write(Servdata)
if Servdata == '4':
motor.write(Servdata)
print "Backwards"
if Servdata == '~':
motor.write(Servdata)
retval = motor.readline()
Serv.send(retval)
else:
pass
motor.write('0')
connection.close()
print addr[0], "Closed Manual Mode"

最后但同样重要的是,客户端 GUI 代码(这也是我认为我的问题所在...):

from socket import *
from PythonCard import model
HOST = ''
PORT = 9000
ADDR = (HOST,PORT)
BUFSIZE = 4096
Client = socket (AF_INET,SOCK_STREAM)
Client.connect((ADDR))
Client.send('M')
class MainWindow(model.Background):
def on_SetSpdBtn_mouseClick(self, event):
spd = self.components.SpdSpn.value
def on_FwdBtn_mouseClick(self, event):
spd = self.components.SpdSpn.value
Client.send('1')
def on_LftBtn_mouseClick(self, event):
spd = self.components.SpdSpn.value
Client.send('2')
def on_RitBtn_mouseClick(self, event):
spd = self.components.SpdSpn.value
Client.send('3')
def on_RevBtn_mouseClick(self, event):
spd = self.components.SpdSpn.value
Client.send('4')
def on_StpBtn_mouseClick(self, event):
spd = self.components.SpdSpn.value
Client.send('0')
def on_GetPing_mouseClick(self, event):
Client.send('~')
retval = Client.recv()
ping_data = retval.strip() # Strip out the newline, if you read an entire line.
split_data = ping_data.split(',')
L_Ping = split_data[0]
R_Ping = split_data[1]
self.components.PingLeft.text = str(L_Ping)
self.components.PingRight.text = str(R_Ping)
app = model.Application(MainWindow)
app.MainLoop()

最佳答案

我想我在这段代码中发现了三个问题;第一个是浪费,第二个可能是你今天来这里的原因,第三个是你认为你今天进来的原因。 :)

忙等中

此代码为 busy waiting用于连接上的数据:

connection.setblocking(0)
print "Connected by", addr[0]
while(1):
try:
Servdata = connection.recv(1)
break
except:
pass

这里又是:

    while(Servdata != 'X'):
Servdata = '9'
try:
Servdata = connection.recv(1)
except:
pass
# ...
else:
pass

这会疯狂地消耗 CPU 周期;最好希望您没有使用电池供电。它也不会给您买任何东西;你也可以调用一个blocking recv()。让 CPU 在等待下一个输入字节时进入休眠状态。 (如果您实际上对任何事情都使用非阻塞,那么忙碌的等待会更有意义,但事实并非如此。如果您想限制服务器阻塞输入的时间,总是有 settimeout() 。但是不要也不要盲目地使用 that,因为这段代码将从切换到阻塞 recv() 中获益最多。)

不向客户端发送数据

        if Servdata == '~':
motor.write(Servdata)
retval = motor.readline()
Serv.send(retval)

我认为这个代码块还没有被执行 :) Serv 没有连接到任何东西,它是一个监听套接字。您可能在这里指的是 connection.send(retval);我在服务器中找不到任何其他实际会向客户端发送数据的线路,所以大概就是这样。

一次全部

客户端中的这段代码有点脆弱,但可能永远不会崩溃:

def on_GetPing_mouseClick(self, event):
Client.send('~')
retval = Client.recv()
ping_data = retval.strip() # strip out the newline, if you read an entire line
split_data = ping_data.split(',')
L_Ping = split_data[0]
R_Ping = split_data[1]
self.components.PingLeft.text = str(L_Ping)
self.components.PingRight.text = str(R_Ping)

此代码假定 recv() 调用将返回一个协议(protocol)消息。 TCP 流不是那样工作的,对等点可以自由发送他们喜欢的任何大小的传出数据。 (TCP/IP 堆栈始终为 combine multiple application-level messages into a single TCP packet。它们还发送比请求更小的数据包,以避免 fragmentation。)

更安全的做法是用从远程对等端接收到的内容填充一个队列,然后解析您的命令/消息的队列。您可能会在队列中找到十个命令,您可能只会找到一个命令的部分——但您的代码需要准备好将部分消息推送到队列中,并使用队列中的完整消息何时可用

这是一些额外的工作,但在不太理想的情况下是安全操作所必需的。您可能永远不会在 LAN 上遇到问题,但在使用无线网络或通过更大的网络路由时会遇到麻烦。

关于python - 如果您不知道有多少数据通过,如何接收套接字信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6300919/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com