我正在创建一个机器人,它将由通过TCP连接接收的命令驱动。因此,我将有一个带有方法的robot类(例如sense()、drive()…)以及TCP连接的类。
为了建立TCP连接,我查看了twisted中的示例。在客户端,我编写了一个用于连接处理的client.py脚本:
from twisted.internet import reactor, protocol
import random
from eventhook import EventHook
import common
#from Common.socketdataobjects import response
# a client protocol
class EchoClient(protocol.Protocol):
"""Once connected, send a message, then print the result."""
def connectionMade(self):
self.transport.write("hello, world!")
#the server should be notified that the connection to the robot has been established
#along with robot state (position)
#eventConnectionEstablishedHook.fire()
def dataReceived(self, data):
print "Server said:", data
self.transport.write("Hello %s" % str(random.randint(1,10)))
'''
serverMessage = common.deserializeJson(data)
command = serverMessage.command
arguments = serverMessage.arguments
#here we get for example command = "DRIVE"
#arguments = {motor1Speed: 50, motor2Speed: 40}
instead of above response, used for testing purposes,
the commands should be extracted from the data and according to the command,
the method in Robot instance should be called.
When the command execution finishes, the self.transport.write() method should be called
to notify the server that the command execution finished
'''
def connectionLost(self, reason):
print "connection lost"
class EchoFactory(protocol.ClientFactory):
protocol = EchoClient
def clientConnectionFailed(self, connector, reason):
print "Connection failed - goodbye!"
reactor.stop()
def clientConnectionLost(self, connector, reason):
print "Connection lost - goodbye!"
reactor.stop()
# this connects the protocol to a server runing on port 8000
def initializeEventHandlers(connectionEstablishedHook):
global connection
connection.established = 0
global eventConnectionEstablishedHook
eventConnectionEstablishedHook = connectionEstablishedHook
def main():
f = EchoFactory()
reactor.connectTCP("localhost", 8000, f)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
除了这个脚本,我还有一个机器人类:
Class Robot(object():
def __init(self)__:
self.position = (0,0)
def drive(self, speedMotor1, speedMotor2, driveTime)
updateMotor1State(speedMotor1)
updateMotor2State(speedMotor2)
time.sleep(driveTime)
#when the execution finished, the finish status should be sent to client in order to inform the server
return "Finished"
def sense(self)
#logic to get the data from the environment
我想做的是从TCP连接接收数据(命令),然后在Robot实例中调用相应的方法。有些过程可能需要更长的时间(例如驾驶),所以我尝试使用事件,但还没有找到使用事件在TCP客户端和机器人之间进行通信的合适方法:
if __name__ == '__main__':
robotController = Robot()
eventController = Controller()
connectionEstablishedHook = EventHook()
client.initializeEventHandlers(connectionEstablishedHook)
eventController.connection = connectionEstablishedHook
client.main()
我尝试创建ClientMainProgram脚本,在那里我想创建一个机器人的实例,一个TCP客户端的实例,并使用事件实现它们之间的通信。
以前,我曾在一个更简单的例子中使用Michael Foord的事件模式来实现事件处理。如果有人能提供这个问题的解决方案或任何可能有助于解决这个问题的类似例子,我将不胜感激。
使用常规Python函数调用可以很容易地表示事件。
例如,如果您的协议如下所示:
from twisted.internet.protocol import Protocol
class RobotController(Protocol):
def __init__(self, robot):
self.robot = robot
def dataReceived(self, data):
for byte in data:
self.commandReceived(byte)
def commandReceived(self, command):
if command == "x00":
# drive:
self.robot.drive()
elif command == "x01":
# sense:
self.robot.sense()
...
(这个例子中使用的协议的细节有些偶然。我选择这个协议是因为它非常简单,几乎没有解析逻辑。对于您的实际应用程序,我建议您使用twisted.protocols.amp
。)
然后,您所需要做的就是确保robot
属性已正确初始化。您可以使用更新的端点API轻松做到这一点,这些API通常可以取代工厂的使用:
from sys import argv
from twisted.internet.endpoints import clientFromString, connectProtocol
from twisted.internet.task import react
def main(reactor, description):
robot = ...
endpoint = clientFromString(reactor, description)
connecting = connectProtocol(endpoint, RobotController(robot))
def connected(controller):
...
connecting.addCallback(connected)
return connecting
react(main, argv[1:])