试图控制Robot时出现Python线程和套接字问题



我在使用Python 3.8.11、线程和套接字包来控制在X/Y轴上移动的机器人时遇到了一个问题。我在Windows 10下。

代码摘要:我使用socket来建立我的python接口和服务器(机器人(之间的连接。机器人需要不断地(至少每2秒(发送一条激活的消息/命令,以便保持连接。因此,我使用线程来实现这一点,通过定义一个函数,该函数将在一个单独的线程中每秒向机器人发送一条活动消息。

我还定义了另一个单独的线程来操作机器人上的基本初始化命令,然后启动在机器人上运行移动命令的while循环(相同的移动命令会发送到机器人,直到我希望它停止(。

我有第三个线程,它寻找停止指令来停止线程和与机器人的连接(当我按下键盘上的q键时(。

代码:

import threading  # to handle multiple threads operating in parallel
import time  # to handle time events
import socket  # to connect Python client to TCP IP server
import keyboard  # to handle keyboard events
# TCP IP parameters of the Server
HOST = '192.168.3.11'
PORT = 3920
# Initializing the Client/Server connection
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_address = (HOST, PORT)
sock.connect(server_address)
# Initializing the Alive message to keep the Client/Server connection alive (message need to be sent at least every 2 seconds otherwise connection is lost)
messageAliveJog = "CRISTART 1234 ALIVEJOG 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 CRIEND"
encodedAliveJog=messageAliveJog.encode('utf-8')
arrayAliveJog=bytearray(encodedAliveJog)
# Initializing the movement message that will be iterated
messageMoveGantryRelative_10x10 = "CRISTART 1234 CMD Move RelativeJoint 10 10 0 0 0 0 0 0 0 30 CRIEND"
encodedMoveGantryRelative_10x10=messageMoveGantryRelative_10x10.encode('utf-8')
arrayMoveGantryRelative_10x10=bytearray(encodedMoveGantryRelative_10x10)
# Initializing the Stop Thread variable
stop_threads = False

# Function to keep Client Server connection alive
def connectGantry():
while True:
global arrayAliveJog
print('Sending Alive')
sock.sendall(arrayAliveJog)
# data = sock.recv(1024)
# print(data)
time.sleep(1)
global stop_threads
if stop_threads:
break
# Function to initiate the robot first moves, and then to iterate the same movement again and again
def moveGantry():
# Command 1: resetting the robot
messageResetGantry = "CRISTART 1234 CMD Reset CRIEND"
encodedResetGantry = messageResetGantry.encode('utf-8')
arrayResetGantry=bytearray(encodedResetGantry)
print("Resetting Gantry")
sock.sendall(arrayResetGantry)
time.sleep(0.1)
# Command 2: Enabling robot motors
messageEnableMotors = "CRISTART 1234 CMD Enable CRIEND"
encodedEnableMotors=messageEnableMotors.encode('utf-8')
arrayEnableMotors=bytearray(encodedEnableMotors)
print("Enabling Motors")
sock.sendall(arrayEnableMotors)
time.sleep(0.1)
# Command 3: Forcing Python client to be pritority client to the Robot
messageSetClientActive = "CRISTART 1234 CMD SetActive true CRIEND"
encodedSetClientActive=messageSetClientActive.encode('utf-8')
arraySetClientActive=bytearray(encodedSetClientActive)
print("Activating Client")
sock.sendall(arraySetClientActive)
time.sleep(0.1)
# Command 4: Moving the robot near its 0 location (X = 5 and Y  = 5 here)
messageMoveGantryTo_5x5 = "CRISTART 1234 CMD Move Joint 5 5 0 0 0 0 0 0 0 30 CRIEND"
encodedMoveGantryTo_5x5=messageMoveGantryTo_5x5.encode('utf-8')
arrayMoveGantryTo_5x5=bytearray(encodedMoveGantryTo_5x5)
print("Moving Gantry to Location 10x10")
sock.sendall(arrayMoveGantryTo_5x5)
time.sleep(10)
# Command 5: Referencing Robot X and Y axes
messageReferenceAxes = "CRISTART 1234 CMD ReferenceAllJoints CRIEND"
encodedReferenceAxes=messageReferenceAxes.encode('utf-8')
arrayReferenceAxes=bytearray(encodedReferenceAxes)
print("Referencing Joints")
sock.sendall(arrayReferenceAxes)
time.sleep(30)
# Command 6: Making sure the robot motors are still enabled after referencing
messageEnableMotors = "CRISTART 1234 CMD Enable CRIEND"
encodedEnableMotors=messageEnableMotors.encode('utf-8')
arrayEnableMotors=bytearray(encodedEnableMotors)
print("Enabling Motors")
sock.sendall(arrayEnableMotors)
time.sleep(0.1)
# Command 7: Defining the Robot motion type
messageMotionTypeJoint = "CRISTART 1234 CMD MotionTypeJoint CRIEND"
encodedMotionTypeJoint=messageMotionTypeJoint.encode('utf-8')
arrayMotionTypeJoint=bytearray(encodedMotionTypeJoint)
print("Defining Motion Type to Joint")
sock.sendall(arrayMotionTypeJoint)
time.sleep(0.1)
# Command 8: Moving the Robot to its starting position
messageMoveGantryTo_10x10 = "CRISTART 1234 CMD Move Joint 100 10 0 0 0 0 0 0 0 30 CRIEND"
encodedMoveGantryTo_10x10=messageMoveGantryTo_10x10.encode('utf-8')
arrayMoveGantryTo_10x10=bytearray(encodedMoveGantryTo_10x10)
print("Moving Gantry to Location 10x10")
sock.sendall(arrayMoveGantryTo_10x10)
time.sleep(10)
# Command 9: Starting the Loop during which the Robot will sequentially move by 10mm on the X axis and 10mm on the Y axis
counterIndex = 1
while True:
global arrayMoveGantryRelative_10x10
print("Moving Gantry by 10x10mm")
sock.sendall(arrayMoveGantryRelative_10x10)
time.sleep(5)
print("Stop number: ", counterIndex)
counterIndex += 1
# Exiting Loop if stop_threads gets True (when key q is pressed)
if stop_threads:
break
# Stopping the threads if key q is pressed
def stopTheThreads():
global stop_threads
while True:
time.sleep(0.1)
if keyboard.read_key() == "q":
stop_threads = True
break
# Initializing the Threads
t1 = threading.Thread(target = connectGantry)
t2 = threading.Thread(target = moveGantry)
t3 = threading.Thread(target = stopTheThreads)
t1.start()
t2.start()
t3.start()

# Waiting for Thread 1 (alive message) to be ended before closing the Client/Server sock connection
t1.join()
print('Ending Connection')
sock.close()

运行此代码时,python接口和机器人之间建立了连接,然后机器人正确初始化并开始循环执行移动命令(在X和Y轴上逐步移动,每5秒移动10毫米(。然而,在while循环中进行了5到10次迭代之后,我将面临以下错误消息:

Exception in thread Thread-2:
Traceback (most recent call last):
File "C:Anaconda3envsEnvNamelibthreading.py", line 932, in _bootstrap_inner
self.run()
File "C:Anaconda3envsEnvNamelibthreading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "c:/Foldername/MoveGantry.py", line 114, in moveGantry
sock.sendall(arrayMoveGantryRelative_10x10)
OSError: [WinError 10038] An operation was attempted on something that is not a socket

该错误从未真正发生在同一步骤(有时错误提到moveGantry中的第82行,而不是上述示例中的第114行(,也从未发生在while循环的相同迭代次数之后(有时5次迭代,有时6次,有时高达10次(。

由于我对线程和套接字连接还很陌生,所以在定义/参数化线程和套接字时可能犯了错误。然而,我很难理解为什么在第一次迭代一切顺利的情况下,一段时间后会出现这种错误。我希望有人能够引导我解决这个问题。

谢谢

我不认为套接字模块是线程安全的。至少不能从多个线程使用同一个套接字。尝试使用队列或线程安全的东西,为要发送到机器人的命令提供某种缓冲区。然后,您可以从多个线程安全地将命令放入该缓冲区,实际上只从一个线程发送所有命令。

最新更新