- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在开发基于 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/
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题? Update the question所以它是on-topic对于堆栈溢出。 9年前关闭。 Improve this que
我有一堆 php 脚本计划在 CentOS 机器上的 cron 中每隔几分钟运行一次。我希望每个脚本在启动时自我检查它的前一个实例是否仍在运行,如果是则停止。 最佳答案 我这样做是为了管理任务并确保它
是否有 bash 命令、程序或 libusb 函数(尽管我没有找到)来指示 USB 设备的 OUT 或 IN 端点是什么? 例如,libusb_interface_descriptor(来自 libu
我如何知道 NSTextField 何时成为第一响应者(即当用户单击它来激活它时,但在他们开始输入之前)。我尝试了 controlTextDidBeginEditing 但直到用户键入第一个字符后才会
我怎么知道我的代码何时完成循环?完成后我还得再运行一些代码,但只有当我在那里写的所有东西都完成后它才能运行。 obj.data.forEach(function(collection) {
我正在使用音频标签,我希望它能计算播放了多少次。 我的代码是这样的: ; ; ; 然后在一个javascript文件中 Var n=0; function doing(onplaying)
我正在尝试向 Package-Explorer 的项目上下文菜单添加一个子菜单。但是,我找不到该菜单的 menuid。 所以我的问题是如何在 eclipse 中找到 menuid? 非常感谢您的帮助。
我有一个名为“下一步”的按钮,它存在于几个 asp.net 页面中。实际上它是在用户控件中。单击“下一步”时,它会调用 JavaScript 中的函数 CheckServicesAndStates。我
我正在尝试在 Visual Studio 中使用 C++ 以纳秒为单位计算耗时。我做了一些测试,结果总是以 00 结尾。这是否意味着我的处理器(Ryzen 7-1800X)不支持 ~1 纳秒的分辨率,
我有一个自定义 ListView ,其中包含一些元素和一个复选框。当我点击一个按钮时。我想知道已检查的元素的位置。下面是我的代码 public class Results extends ListAc
如何在使用 J2ME 编写的应用程序中获取网络运营商名称? 我最近正在尝试在 Nokia s40 上开发一个应用程序,它应该具有对特定网络运营商的独占访问权限。有没有这样的API或库? 最佳答案 没有
我使用服务器客户端组件,当在此组件的 TransferFile 事件中接收文件时,我使用警报消息组件。所以我希望,如果用户单击警报消息,程序将继续执行 TransferFile 事件中的代码,以在单击
如果我创建一个类A具有一些属性,例如 a, b, c我创建对象 A x1; A x2; A x3; ... A xN 。有没有办法在同一个类中创建一个方法来检索我创建的所有对象?我想创建类似 stat
我正在制作一个应用程序,其中包含相同布局的 81 个按钮。它们都被称为我创建的名为“Tile”的对象。问题是这些图 block 存储在数组中,因此我需要知道以 int 格式单击了哪个按钮才能调用图 b
UIProgressView有这个setProgress:animated: API。 有没有办法确切知道动画何时停止? 我的意思是这样的? [myProgress setProgress:0.8f
我正在使用两个 jQuery 队列,我希望其中一个队列在另一个队列完成后出队。我怎么知道第一个是否完成?我应该使用第三个队列吗?! 这是我所拥有的: var $q = $({}); $q.que
jQuery 中有没有一种方法可以知道是否至少有一个复选框已被选中? 我有一个包含很多复选框的表单,每个复选框都不同。 我需要一种 jQuery 的方式来表达这样的内容,这就是逻辑: If at le
给定 2 个选择 100 50 100 在这两种情况下,我都想在 .example 中获取数字,使用相同的选择器或者以某种方式知道 .no-text 和 之间的区别。带文字 执行
我在我的应用程序中使用 System.ComponentModel.BindingList 作为 DataGridView.DataSource。该列表非常大,需要几秒钟才能绘制到 DataGridV
我想知道用户在 Android 中选择的默认键盘。我知道我可以使用 InputMethodManager 访问已启用的输入法列表,但我想知道用户当前使用的是哪一个。 到目前为止,我已经尝试获取当前的输
我是一名优秀的程序员,十分优秀!