Python,用于与Zaber TLSR300B通信的pyserial程序
我还是新来的,所以如果我犯了任何错误或者我的问题不够具体,我道歉,请纠正我!我正在编写一个程序,通过串行连接控制激光实验室中的两个Zaber TLSR300B线性运动轨迹。我使用pyserial与他们通信没有问题,我能够写入和读取数据,没有问题。我的问题更多的是关于如何构建我的程序以实现所需的功能(我很少接受正式的编程培训) 我想让程序做的是提供一些方法,允许用户向曲目发送命令,然后返回曲目响应。但是,我不希望程序在检查响应时挂起,因此我不能只写写写命令后跟读命令的方法。对于某些命令,轨迹会立即响应(返回ID、返回当前位置等),但对于其他命令,轨迹会在执行请求的操作(移动到位置、移动回家等)后立即响应。例如,如果发送了move_绝对命令,轨迹将移动到所需位置,然后发送带有新位置的回复。此外,轨道可以通过物理旋钮手动移动,这使得轨道在移动时不断发送其当前位置(这就是为什么我需要不断读取串行数据) 我在下面附加了代码,在这里我实现了一个线程,当有数据要读取时从串行端口读取数据并将其放入队列中。然后,另一个线程从队列中获取项目并对其进行处理,修改存储每个曲目的当前属性的ZaberTLSR300B对象的适当值。底部的方法是我希望用户能够调用的一些方法。它们只需将命令写入串行端口,然后由持续运行的读取线程拾取和处理响应 我遇到的主要问题是,这些方法不知道跟踪响应的内容,因此无法返回回复,我想不出解决方法。所以我不能写这样的东西:Python,用于与Zaber TLSR300B通信的pyserial程序,python,multithreading,serial-port,pyserial,zaber,Python,Multithreading,Serial Port,Pyserial,Zaber,我还是新来的,所以如果我犯了任何错误或者我的问题不够具体,我道歉,请纠正我!我正在编写一个程序,通过串行连接控制激光实验室中的两个Zaber TLSR300B线性运动轨迹。我使用pyserial与他们通信没有问题,我能够写入和读取数据,没有问题。我的问题更多的是关于如何构建我的程序以实现所需的功能(我很少接受正式的编程培训) 我想让程序做的是提供一些方法,允许用户向曲目发送命令,然后返回曲目响应。但是,我不希望程序在检查响应时挂起,因此我不能只写写写命令后跟读命令的方法。对于某些命令,轨迹会立即
newPosition = TrackManager.move_absolute(track 1, 5000)
或
这就是我希望用户最终能够做到的(也是因为我希望在将来在此基础上实现某种GUI)
不管怎样,我这样做对吗?或者有没有更干净的方法来实现这种行为?我愿意完全重写一切,如果需要的话
谢谢,如果有什么不清楚的请告诉我
Zaber TLSR300B手册(如需要):
代码:
田径经理班
import serial
import threading
import struct
import time
from collections import deque
from zaberdevices import ZaberTLSR300B
class TrackManager:
def __init__(self):
self.serial = serial.Serial("COM5",9600,8,'N',timeout=None)
self.track1 = ZaberTLSR300B(1, self.serial)
self.track2 = ZaberTLSR300B(2, self.serial)
self.trackList = [self.track1, self.track2]
self.serialQueue = deque()
self.runThread1 = True
self.thread1 = threading.Thread(target=self.workerThread1)
self.thread1.start()
self.runThread2 = True
self.thread2 = threading.Thread(target=self.workerThread2)
self.thread2.start()
def workerThread1(self):
while self.runThread1 == True:
while self.serial.inWaiting() != 0:
bytes = self.serial.read(6)
self.serialQueue.append(struct.unpack('<BBl', bytes))
def workerThread2(self):
while self.runThread2 == True:
try:
reply = self.serialQueue.popleft()
for track in self.trackList:
if track.trackNumber == reply[0]:
self.handleReply(track, reply)
except:
continue
def handleReply(self, track, reply):
if reply[1] == 10:
track.update_position(reply[2])
elif reply[1] == 16:
track.storedPositions[address] = track.position
elif reply[1] == 20:
track.update_position(reply[2])
elif reply[1] == 21:
track.update_position(reply[2])
elif reply[1] == 60:
track.update_position(reply[2])
def move_absolute(self, trackNumber, position):
packet = struct.pack("<BBl", trackNumber, 20, position)
self.serial.write(packet)
def move_relative(self, trackNumber, distance):
packet = struct.pack("<BBl", trackNumber, 21, distance)
self.serial.write(packet)
def return_current_position(self, trackNumber):
packet = struct.pack("<BBl", trackNumber, 60, 0)
self.serial.write(packet)
def return_stored_position(self, trackNumber, address):
packet = struct.pack("<BBl", trackNumber, 17, address)
self.serial.write(packet)
def store_current_position(self, trackNumber, address):
packet = struct.pack("<BBl", trackNumber, 16, address)
self.serial.write(packet)
因此,当一个多线程应用程序需要共享相同的数据时,我这样做的方式是实现我自己的“locker”。基本上你的线程会调用这个ChekWrite方法,它会返回true或false,如果为true,它会将锁设置为true,然后通过调用其中的另一个方法来使用共享资源,完成后,它会将锁设置为false。如果没有,它将等待一段时间,然后重试。检查写入将是它自己的类。你可以在网上寻找一些多线程锁的例子,你应该是黄金。此外,这一切都是基于我对你的代码的解释和上面的描述。。。我喜欢照片 /不适用 编辑
是我的错。当ListenerThread获取数据并需要将其写入响应堆栈时,它需要请求权限。因此,它将调用一个方法CheckWrite,它是静态的,这个方法将把数据作为一个参数,并返回一个位或布尔值。在这个函数中,它将检查它是否正在使用,我们称之为锁定。如果它被锁定,它将返回false,您的侦听器将等待一段时间,然后重试。如果它是解锁的。它会将其设置为锁定,然后继续写入响应堆栈。一旦完成,它将解锁该方法。在响应堆栈上,必须实现相同的功能。当我创建图形时,我忘记了它。您的主程序或任何想要读取数据的程序都需要请求读取权限,锁定锁定锁数值,然后继续读取数据并清除它。此外,您还可以完全摆脱堆栈,并在写入方法中包含一个方法,该方法继续并对数据执行逻辑。我想把它分开,但每个都是自己的。控制器上有一个选项,可以禁用所有不立即跟随命令的回复。您可以通过启用的第0位和第5位来实现这一点。这些位对应于“禁用自动回复”和“禁用手动移动跟踪”。位11默认启用,因此启用这些位的组合值为2081
我的建议是禁用这些额外的响应,这样您就可以依赖可预测且可靠的命令->响应模型。例如,要移动设备,您将发送move命令,但从不查找来自该命令的响应。要检查移动是否已完成,您可以使用命令并读取位置响应,或使用返回状态(Cmd_54)命令检查设备是否繁忙(即移动)或空闲 谢谢你的回复!我理解您的建议对于管理对“serialQueue”deque的访问非常重要,因为一个线程正在向其写入,另一个线程正在从中读取。然而,也许我遗漏了一些东西,但是这如何帮助从write函数中获取回复数据呢?
import serial
import threading
import struct
import time
from collections import deque
from zaberdevices import ZaberTLSR300B
class TrackManager:
def __init__(self):
self.serial = serial.Serial("COM5",9600,8,'N',timeout=None)
self.track1 = ZaberTLSR300B(1, self.serial)
self.track2 = ZaberTLSR300B(2, self.serial)
self.trackList = [self.track1, self.track2]
self.serialQueue = deque()
self.runThread1 = True
self.thread1 = threading.Thread(target=self.workerThread1)
self.thread1.start()
self.runThread2 = True
self.thread2 = threading.Thread(target=self.workerThread2)
self.thread2.start()
def workerThread1(self):
while self.runThread1 == True:
while self.serial.inWaiting() != 0:
bytes = self.serial.read(6)
self.serialQueue.append(struct.unpack('<BBl', bytes))
def workerThread2(self):
while self.runThread2 == True:
try:
reply = self.serialQueue.popleft()
for track in self.trackList:
if track.trackNumber == reply[0]:
self.handleReply(track, reply)
except:
continue
def handleReply(self, track, reply):
if reply[1] == 10:
track.update_position(reply[2])
elif reply[1] == 16:
track.storedPositions[address] = track.position
elif reply[1] == 20:
track.update_position(reply[2])
elif reply[1] == 21:
track.update_position(reply[2])
elif reply[1] == 60:
track.update_position(reply[2])
def move_absolute(self, trackNumber, position):
packet = struct.pack("<BBl", trackNumber, 20, position)
self.serial.write(packet)
def move_relative(self, trackNumber, distance):
packet = struct.pack("<BBl", trackNumber, 21, distance)
self.serial.write(packet)
def return_current_position(self, trackNumber):
packet = struct.pack("<BBl", trackNumber, 60, 0)
self.serial.write(packet)
def return_stored_position(self, trackNumber, address):
packet = struct.pack("<BBl", trackNumber, 17, address)
self.serial.write(packet)
def store_current_position(self, trackNumber, address):
packet = struct.pack("<BBl", trackNumber, 16, address)
self.serial.write(packet)
class ZaberTLSR300B:
def __init__(self, trackNumber, serial):
self.trackNumber = trackNumber
self.serial = serial
self.position = None
self.storedPositions = []
def update_position(self, position):
self.position = position