Beispiel #1
0
    def __init__(self):
        Thread.__init__(self)
        self.name = "WalleServer"

        self.number = 0
        self.azimuth = 0.0  # position sense, azimuth from north
        self.turning_to_object = False  # Are we turning to see an object
        self.hearing_angle = 0.0  # device hears sound from this angle, device looks to its front
        # to the azimuth direction
        self.observation_angle = 0.0  # turn until azimuth is this angle

        self.leftPower = 0.0  # moving
        self.rightPower = 0.0

        self.number = 0
        self.in_axon = Axon()  # global queue for senses to put sensations to walle
        self.out_axon = Axon()  # global queue for walle to put sensations to external senses

        # starting build in capabilities/senses
        # we have capability to move
        if MANUAL:
            self.romeo = ManualRomeo()
        else:
            self.romeo = Romeo()
        # we have hearing (positioning of object using sounds)
        self.hearing = Hearing(self.in_axon)

        # starting tcp server as nerve pathway to external senses to connect
        # we have azimuth sense (our own position detection)
        self.tcpServer = TCPServer(out_axon=self.in_axon, in_axon=self.out_axon, server_address=(HOST, PORT))

        self.running = False
        self.turnTimer = Timer(WalleServer.ACTION_TIME, self.stopTurn)

        self.calibrating = False  # are we calibrating
        self.calibrating_angle = 0.0  # calibrate device hears sound from this angle, device looks to its front
        # self.calibratingTimer = Timer(WalleServer.ACTION_TIME, self.stopCalibrating)
        print "WalleServer: Calibrate version"
Beispiel #2
0
class WalleServer(Thread):
    """
    Controls Walle-robot. Walle has capabilities like moving, hearing, seeing and position sense.
    Technically we use socket servers to communicate with external devices. Romeo board is controlled
    using library using USB. We use USB-microphones and Raspberry pi camera.
    
    Walle emulates sensorys (camera, microphone, mobile phone) that have emit sensations to "brain" that has state and memory and gives
    commands (technically Sensation class instances) to muscles (Romeo Board, mobile phone)
    
    Sensations from integrated sensorys are transferred By axons ad in real organs, implemented as Queue, which is thread safe.
    Every sensory runs in its own thread as real sensorys, independently.
    External Sensorys are handled using sockets.
    """

    TURN_ACCURACYFACTOR = math.pi * 10.0 / 180.0
    FULL_TURN_FACTOR = math.pi * 45.0 / 180.0

    DEFAULT_OBSERVATION_DISTANCE = 3.0

    ACTION_TIME = 1.0

    def __init__(self):
        Thread.__init__(self)
        self.name = "WalleServer"

        self.number = 0
        self.azimuth = 0.0  # position sense, azimuth from north
        self.turning_to_object = False  # Are we turning to see an object
        self.hearing_angle = 0.0  # device hears sound from this angle, device looks to its front
        # to the azimuth direction
        self.observation_angle = 0.0  # turn until azimuth is this angle

        self.leftPower = 0.0  # moving
        self.rightPower = 0.0

        self.number = 0
        self.in_axon = Axon()  # global queue for senses to put sensations to walle
        self.out_axon = Axon()  # global queue for walle to put sensations to external senses

        # starting build in capabilities/senses
        # we have capability to move
        if MANUAL:
            self.romeo = ManualRomeo()
        else:
            self.romeo = Romeo()
        # we have hearing (positioning of object using sounds)
        self.hearing = Hearing(self.in_axon)

        # starting tcp server as nerve pathway to external senses to connect
        # we have azimuth sense (our own position detection)
        self.tcpServer = TCPServer(out_axon=self.in_axon, in_axon=self.out_axon, server_address=(HOST, PORT))

        self.running = False
        self.turnTimer = Timer(WalleServer.ACTION_TIME, self.stopTurn)

        self.calibrating = False  # are we calibrating
        self.calibrating_angle = 0.0  # calibrate device hears sound from this angle, device looks to its front
        # self.calibratingTimer = Timer(WalleServer.ACTION_TIME, self.stopCalibrating)
        print "WalleServer: Calibrate version"

    def run(self):
        print "Starting " + self.name

        # starting other threads/senders/capabilities

        self.running = True
        self.hearing.start()
        print "WalleServer: starting TCPServer"
        self.tcpServer.start()

        while self.running:
            sensation = self.in_axon.get()
            print "WalleServer: got sensation from queue " + str(sensation)
            self.process(sensation)
            # as a test, echo everything to external device
            # self.out_axon.put(sensation)

        self.tcpServer.stop()
        self.hearing.stop()

    def stop(self):
        self.running = False

    def process(self, sensation):
        print "WalleServer.process: " + time.ctime(sensation.getTime()) + " " + str(sensation)
        if sensation.getSensationType() == Sensation.SensationType.Drive:
            print "Walleserver.process Sensation.SensationType.Drive"
        elif sensation.getSensationType() == Sensation.SensationType.Stop:
            print "Walleserver.process Sensation.SensationType.Stop"
            self.stop()
        elif sensation.getSensationType() == Sensation.SensationType.Who:
            print "Walleserver.process Sensation.SensationType.Who"
        elif sensation.getSensationType() == Sensation.SensationType.HearDirection:
            print "Walleserver.process Sensation.SensationType.HearDirection"
            # inform external senses that we remember now hearing
            self.out_axon.put(sensation)
            self.hearing_angle = sensation.getHearDirection()
            if self.calibrating:
                print "Walleserver.process Calibrating hearing_angle " + str(
                    self.hearing_angle
                ) + " calibrating_angle " + str(self.calibrating_angle)
            else:
                self.observation_angle = self.add_radian(
                    original_radian=self.azimuth, added_radian=self.hearing_angle
                )  # object in this angle
                print "Walleserver.process create Sensation.SensationType.Observation"
                self.in_axon.put(
                    Sensation(
                        number=++self.number,
                        sensationType=Sensation.SensationType.Observation,
                        observationDirection=self.observation_angle,
                        observationDistance=WalleServer.DEFAULT_OBSERVATION_DISTANCE,
                    )
                )
                # mark hearing sensation to be processed to set direction out of memory, we forget it
                sensation.setDirection(Sensation.Direction.Out)
                # inform external senses that we don't remember hearing any more
                self.out_axon.put(sensation)
        elif sensation.getSensationType() == Sensation.SensationType.Azimuth:
            if not self.calibrating:
                print "Walleserver.process Sensation.SensationType.Azimuth"
                # inform external senses that we remember now azimuth
                # self.out_axon.put(sensation)
                self.azimuth = sensation.getAzimuth()
                self.turn()
        elif sensation.getSensationType() == Sensation.SensationType.Observation:
            if not self.calibrating:
                print "Walleserver.process Sensation.SensationType.Observation"
                # inform external senses that we remember now observation
                self.out_axon.put(sensation)
                self.observation_angle = sensation.getObservationDirection()
                self.turn()
        elif sensation.getSensationType() == Sensation.SensationType.Picture:
            print "Walleserver.process Sensation.SensationType.Picture"
        elif sensation.getSensationType() == Sensation.SensationType.Calibrate:
            print "Walleserver.process Sensation.SensationType.Calibrate"
            if sensation.getMemory() == Sensation.Memory.Working:
                if sensation.getDirection() == Sensation.Direction.In:
                    print "Walleserver.process asked to start calibrating mode"
                    self.calibrating = True
                else:
                    print "Walleserver.process asked to stop calibrating mode"
                    self.calibrating = False
                # ask external senses to to set same calibrating mode
                self.out_axon.put(sensation)
            elif sensation.getMemory() == Sensation.Memory.Sensory:
                if self.calibrating:
                    if self.turning_to_object:
                        print "Walleserver.process turning_to_object, can't start calibrate activity yet"
                    else:
                        # allow requester to start calibration activaties
                        if sensation.getDirection() == Sensation.Direction.In:
                            print "Walleserver.process asked to start calibrating activity"
                            self.calibrating_angle = sensation.getHearDirection()
                            self.hearing.setCalibrating(calibrating=True, calibrating_angle=self.calibrating_angle)
                            sensation.setDirection(Sensation.Direction.In)
                            self.out_axon.put(sensation)
                            # self.calibratingTimer = Timer(WalleServer.ACTION_TIME, self.stopCalibrating)
                            # self.calibratingTimer.start()
                        else:
                            print "Walleserver.process asked to stop calibrating activity"
                            self.hearing.setCalibrating(calibrating=False, calibrating_angle=self.calibrating_angle)
                            # self.calibratingTimer.cancel()
                else:
                    print "Walleserver.process asked calibrating activity WITHOUT calibrate mode, IGNORED"

        elif sensation.getSensationType() == Sensation.SensationType.Capability:
            print "Walleserver.process Sensation.SensationType.Capability"
        elif sensation.getSensationType() == Sensation.SensationType.Unknown:
            print "Walleserver.process Sensation.SensationType.Unknown"

    def turn(self):
        # calculate new power to turn or continue turning
        self.leftPower, self.rightPower = self.getPower()
        if self.turning_to_object:
            print "WalleServer.turn: self.hearing_angle " + str(self.hearing_angle) + " self.azimuth " + str(
                self.azimuth
            )
            print "WalleServer.turn: turn to " + str(self.observation_angle)
            if math.fabs(self.leftPower) < Romeo.MINPOWER or math.fabs(self.rightPower) < Romeo.MINPOWER:
                self.stopTurn()
                print "WalleServer.turn: Turn is ended"
                self.turnTimer.cancel()
            else:
                print "WalleServer.turn: powers adjusted to " + str(self.leftPower) + " " + str(self.rightPower)
                self.number = self.number + 1
                sensation, picture = self.romeo.processSensation(
                    Sensation(
                        number=self.number, sensationType="D", leftPower=self.leftPower, rightPower=self.rightPower
                    )
                )
                self.leftPower = sensation.getLeftPower()  # set motors in opposite power to turn in place
                self.rightPower = sensation.getRightPower()  # set motors in opposite power to turn in place

        else:
            if math.fabs(self.leftPower) >= Romeo.MINPOWER or math.fabs(self.rightPower) >= Romeo.MINPOWER:
                self.turning_to_object = True
                # adjust hearing
                # if turn, don't hear sound, because we are giving moving sound
                # we want hear only sounds from other objects
                self.hearing.setOn(not self.turning_to_object)
                print "WalleServer.turn: powers initial to " + str(self.leftPower) + " " + str(self.rightPower)
                self.number = self.number + 1
                sensation, picture = self.romeo.processSensation(
                    Sensation(
                        number=self.number, sensationType="D", leftPower=self.leftPower, rightPower=self.rightPower
                    )
                )
                self.leftPower = sensation.getLeftPower()  # set motors in opposite power to turn in place
                self.rightPower = sensation.getRightPower()  # set motors in opposite power to turn in place
                self.turnTimer = Timer(WalleServer.ACTION_TIME, self.stopTurn)
                self.turnTimer.start()

    def stopTurn(self):
        self.turning_to_object = False
        self.leftPower = 0.0  # set motors in opposite power to turn in place
        self.rightPower = 0.0
        print "WalleServer.stopTurn: Turn is stopped/cancelled"

        print "WalleServer.stopTurn: powers to " + str(self.leftPower) + " " + str(self.rightPower)

        self.hearing.setOn(not self.turning_to_object)

        self.number = self.number + 1
        # test=Sensation.SensationType.Drive
        sensation, picture = self.romeo.processSensation(
            Sensation(number=self.number, sensationType="D", leftPower=self.leftPower, rightPower=self.rightPower)
        )
        self.leftPower = sensation.getLeftPower()  # set motors in opposite power to turn in place
        self.rightPower = sensation.getRightPower()
        print "WalleServer.stopTurn: powers set to " + str(self.leftPower) + " " + str(self.rightPower)

    #   def stopCalibrating(self):
    #       self.calibrating=False
    #       print "WalleServer.stopCalibrating: Calibrating mode is stopped/cancelled"

    def add_radian(self, original_radian, added_radian):
        result = original_radian + added_radian
        if result > math.pi:
            return -math.pi + (result - math.pi)
        if result < -math.pi:
            return math.pi - (result - math.pi)
        return result

    def getPower(self):
        leftPower = 0.0  # set motor in opposite power to turn in place
        rightPower = 0.0

        if math.fabs(self.observation_angle - self.azimuth) > WalleServer.TURN_ACCURACYFACTOR:
            power = (self.observation_angle - self.azimuth) / WalleServer.FULL_TURN_FACTOR
            if power > 1.0:
                power = 1.0
            if power < -1.0:
                power = -1.0
            if math.fabs(power) < Romeo.MINPOWER:
                power = 0.0
            leftPower = power  # set motorn in opposite power to turn in place
            rightPower = -power
        if math.fabs(leftPower) < Romeo.MINPOWER or math.fabs(rightPower) < Romeo.MINPOWER:
            leftPower = 0.0  # set motors in opposite power to turn in place
            rightPower = 0.0

        # test system has so little power, that we must run it at full speed
        #       if leftPower > Romeo.MINPOWER:
        #           leftPower = 1.0           # set motorn in opposite pover to turn in place
        #           rightPower = -1.0
        #       elif leftPower < -Romeo.MINPOWER:
        #           leftPower = -1.0           # set motorn in opposite pover to turn in place
        #           rightPower = 1.0

        return leftPower, rightPower