1

I am creating a robot which is going to be driven by the commands received over TCP connection. Therefore, I will have a robot class with methods (e.g. sense(), drive()...) and the class for TCP connection.

To establish TCP connection, I looked at examples from twisted. On the client side, I have written a client.py script for connection handling:

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()

Beside this script, I have a robot class:

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

What I would like to do, is to receive the data(commands) from TCP connection and then call the according method in Robot instance. Some procedures might take longer (e.g. driving), so I tried to use events, but haven't figured out the appropriate way to communicate between TCP client and robot using events:

if __name__ == '__main__':
    robotController = Robot()
    eventController = Controller()
    connectionEstablishedHook = EventHook()
    client.initializeEventHandlers(connectionEstablishedHook)
    eventController.connection = connectionEstablishedHook
    client.main()

I tried to create ClientMainProgram script, where I wanted to create an instance of a robot, an instance of TCP client and implement the communication between them using events.

Previously I have managed to implement event handling using Michael Foord's events pattern on a simpler example. I would be very thankful if anyone could provide the solution to this question or any similar example which might be helpful to solve this problem.

Niko Gamulin
  • 66,025
  • 95
  • 221
  • 286
  • Have a look at XMLRPC, pickle, json, Pyro, HTTP, REST. They exist. Question: What are the arguments to functions? Do you transfer callbacks, references? Do you want to implement your own protocol? http://stackoverflow.com/a/21644326/1320237 – User Feb 27 '14 at 10:41
  • I edited the Robot psseudo function in order to make it more clear. Anyway, the data, received from the server, should be through client passed to robot instance to control the robot. When the robot finishes executing an action, it should send the data back to server. – Niko Gamulin Feb 27 '14 at 11:12

1 Answers1

1

Events are easily represented using regular Python function calls.

For example, if your protocol looks like this:

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()
        ...

(The specifics of the protocol used in this example are somewhat incidental. I picked this protocol because it's very simple and has almost no parsing logic. For your real application I suggest you use twisted.protocols.amp.)

Then all you need to do is make sure the robot attribute is properly initialized. You can do this easily using the somewhat newer endpoint APIs that can often replace use of factories:

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:])
Jean-Paul Calderone
  • 47,755
  • 6
  • 94
  • 122