Example #1
0
class FileDialog(DirectObject):

    def __init__(self, title, initial_status, callback):
        self.frmLeft = -.7
        self.frmBottom = -.12
        self.frmRight = .7
        self.frmTop = .12
        
        self.frmWidth = self.frmRight - self.frmLeft
        self.frmHeight = self.frmTop - self.frmBottom
        
        self.title = title
        self.initial_status = initial_status
        self.callback = callback
        
        self.result = None
        self.done = 0
            
            
    def activate(self):
        # create main dialog frame
        # Note: frame position references the CENTER of the frame
        self.frm = DirectFrame(
            pos = (0,0,0),
            frameSize = (self.frmLeft, self.frmRight,self.frmBottom, self.frmTop),
            relief = DGG.RIDGE,
            borderWidth = (0.01, 0.01),
            frameColor = (0.6, 0.6, 0.6, 1.0))
        
        self.frm.reparentTo(base.aspect2d)
        
        # Note: wonderfully enough, label position on the other hand
        # references the CENTER of the LEFT border of the label!
        titleLabel = DirectLabel(text = self.title,
            scale = 0.04,
            frameColor = (0.5, 0.5, 0.5, 1),
            relief = DGG.RIDGE,
            borderWidth = (0.01, 0.01),
            text_align = TextNode.ALeft)
            
        titleLabel.setPos(-self.frmWidth/2+.02, 0, self.frmHeight/2-.045)
        titleLabel.reparentTo(self.frm)
        
        sc = .04     
        self.dir_edit_field = DirectEntry(
            text = '',      # prompt text
            scale = sc,
            frameColor = (0.65, 0.65, 0.65, 1),
            command=self.setText,
            width = 32,
            numLines = 1,
            focus = 1,
            focusInCommand=self.efFocusIn,
            )

        self.dir_edit_field.setPos(-self.frmWidth/2+.02, 0, self.frmHeight/2-.13)
        self.dir_edit_field.reparentTo(self.frm)

        self.statusLabel = DirectLabel(text = self.initial_status,
            scale = 0.04,
            frameColor = (0.6, 0.6, 0.6, 1),
            # relief = DGG.RIDGE,
            # borderWidth = (0.01, 0.01),
            text_align = TextNode.ALeft)
            
        self.statusLabel.setPos(-self.frmWidth/2+.02, 0, self.frmHeight/2-.2)
        self.statusLabel.reparentTo(self.frm)

    # call this if you need to run a form before your mainloop starts steppping the taskMgr
    def run(self):
        while self.done != 1:
            taskMgr.step()

        taskMgr.step()          # once more to make the last output from the dialog visible
                                # while we load a zone
        self.frm.removeNode()

    def end(self):
        self.frm.removeNode()
        

    # callback function to set  text: called by the Panda3d taskMgr when the user
    # has entered something into the DirectEntry widget
    def setText(self, textEntered):
        print 'dir_edit_field::setText:', textEntered
        self.done = self.callback(textEntered)
        if self.done != 1:
            self.dir_edit_field['focus'] = 1

                
    #clear the text
    def efFocusIn(self):
        print 'focus in'
        self.dir_edit_field.enterText('')
        
    def setStatus(self, status):
        self.statusLabel['text'] = status
Example #2
0
class FileDialog(DirectObject):
    def __init__(self, title, initial_status, callback):
        self.frmLeft = -.7
        self.frmBottom = -.12
        self.frmRight = .7
        self.frmTop = .12

        self.frmWidth = self.frmRight - self.frmLeft
        self.frmHeight = self.frmTop - self.frmBottom

        self.title = title
        self.initial_status = initial_status
        self.callback = callback

        self.result = None
        self.done = 0

    def activate(self):
        # create main dialog frame
        # Note: frame position references the CENTER of the frame
        self.frm = DirectFrame(pos=(0, 0, 0),
                               frameSize=(self.frmLeft, self.frmRight,
                                          self.frmBottom, self.frmTop),
                               relief=DGG.RIDGE,
                               borderWidth=(0.01, 0.01),
                               frameColor=(0.6, 0.6, 0.6, 1.0))

        self.frm.reparentTo(base.aspect2d)

        # Note: wonderfully enough, label position on the other hand
        # references the CENTER of the LEFT border of the label!
        titleLabel = DirectLabel(text=self.title,
                                 scale=0.04,
                                 frameColor=(0.5, 0.5, 0.5, 1),
                                 relief=DGG.RIDGE,
                                 borderWidth=(0.01, 0.01),
                                 text_align=TextNode.ALeft)

        titleLabel.setPos(-self.frmWidth / 2 + .02, 0,
                          self.frmHeight / 2 - .045)
        titleLabel.reparentTo(self.frm)

        sc = .04
        self.dir_edit_field = DirectEntry(
            text='',  # prompt text
            scale=sc,
            frameColor=(0.65, 0.65, 0.65, 1),
            command=self.setText,
            width=32,
            numLines=1,
            focus=1,
            focusInCommand=self.efFocusIn,
        )

        self.dir_edit_field.setPos(-self.frmWidth / 2 + .02, 0,
                                   self.frmHeight / 2 - .13)
        self.dir_edit_field.reparentTo(self.frm)

        self.statusLabel = DirectLabel(
            text=self.initial_status,
            scale=0.04,
            frameColor=(0.6, 0.6, 0.6, 1),
            # relief = DGG.RIDGE,
            # borderWidth = (0.01, 0.01),
            text_align=TextNode.ALeft)

        self.statusLabel.setPos(-self.frmWidth / 2 + .02, 0,
                                self.frmHeight / 2 - .2)
        self.statusLabel.reparentTo(self.frm)

    # call this if you need to run a form before your mainloop starts steppping the taskMgr
    def run(self):
        while self.done != 1:
            taskMgr.step()

        taskMgr.step(
        )  # once more to make the last output from the dialog visible
        # while we load a zone
        self.frm.removeNode()

    def end(self):
        self.frm.removeNode()

    # callback function to set  text: called by the Panda3d taskMgr when the user
    # has entered something into the DirectEntry widget
    def setText(self, textEntered):
        print 'dir_edit_field::setText:', textEntered
        self.done = self.callback(textEntered)
        if self.done != 1:
            self.dir_edit_field['focus'] = 1

    #clear the text
    def efFocusIn(self):
        print 'focus in'
        self.dir_edit_field.enterText('')

    def setStatus(self, status):
        self.statusLabel['text'] = status
class DroneManager(DirectObject.DirectObject):
    def __init__(self, base, droneList, delay):
        self.base = base
        # the actual dimensions of the bcs drone lab in meters
        # self.roomSize = Vec3(3.40, 4.56, 2.56)
        # confined dimensions because the room and drone coordinates dont match up yet.
        # Also, flying near the windows/close to walls/too high often makes the llighthouse positioning system loose track
        self.roomSize = Vec3(1.5, 2.5, 1.7)
        self.initDrones(droneList)
        self.initUI()

        self.currentFormation = 0
        self.isRotating = False

        self.currentTimeslot = 0

        self.timeslotLengthMilli = delay

    def initDrones(self, droneList):
        """Initializes the drones defined in droneList."""
        self.isStarted = False
        self.isConnected = False
        self.drones = []  # this is the list of all drones
        self.currentDronePos = [
        ]  # this is the list of the most recent position that was sent by each drone

        if droneList == []:
            print("No drones to spawn")
        else:
            for i in range(0, len(droneList)):
                position = droneList[i][0]
                uri = droneList[i][1]
                self.drones.append(Drone(self, position, uri=uri))

        self.base.taskMgr.add(self.updateDronesTask, "UpdateDrones")
        self.base.taskMgr.add(self.updateTimeslotTask, "UpdateTimeslot")

    def updateDronesTask(self, task):
        """Run the update methods of all drones."""
        for drone in self.drones:
            drone.update()
        return task.cont

    def updateTimeslotTask(self, task):
        timeslotAmount = 2
        task.delayTime = self.timeslotLengthMilli / 1000

        self.currentTimeslot += 1
        if self.currentTimeslot >= timeslotAmount:
            self.currentTimeslot = 0

        for drone in self.drones:
            drone.updateSentPosition(self.currentTimeslot)

        return task.again

    def initUI(self):
        # initialize drone control panel
        buttonSize = (-4, 4, -.2, .8)
        buttonDistance = 0.15

        entrySize = (0, 2, -.2, .8)

        # frame = DirectFrame(frameColor=(.2, .2, .2, 1), frameSize=(-.5, .5, -.7, .15), pos=(-.9, 0, -.6), scale=.5)
        frame = DirectFrame(frameColor=(.2, .2, .2, 1),
                            frameSize=(-.5, .5, -.7, .15),
                            pos=(-.9, 0, -.4),
                            scale=.5)

        button = DirectButton(text="Start",
                              scale=.1,
                              frameSize=buttonSize,
                              command=self.startLandAll)
        button["extraArgs"] = [button]
        button.reparentTo(frame)

        button = DirectButton(text="Random Target",
                              scale=.1,
                              frameSize=buttonSize,
                              command=self.setRandomTargets)
        button.reparentTo(frame)
        button.setPos(Vec3(0, 0, -1 * buttonDistance))

        button = DirectButton(text="Stop",
                              scale=.1,
                              frameSize=buttonSize,
                              command=self.stopAll)
        button.reparentTo(frame)
        button.setPos(Vec3(0, 0, -2 * buttonDistance))

        button = DirectButton(text="Return",
                              scale=.1,
                              frameSize=buttonSize,
                              command=self.returnToWaitingPosition)
        button.reparentTo(frame)
        button.setPos(Vec3(0, 0, -3 * buttonDistance))

        button = DirectButton(text="Connect",
                              scale=.1,
                              frameSize=buttonSize,
                              command=self.toggleConnections)
        button["extraArgs"] = [button]
        button.reparentTo(frame)
        button.setPos(Vec3(0, 0, -4 * buttonDistance))

        button = DirectButton(text="Rotate",
                              scale=.1,
                              frameSize=buttonSize,
                              command=self.toggleRotation)
        button.reparentTo(frame)
        button.setPos(Vec3(0, 0, -5 * buttonDistance))

        button = DirectButton(text="Move",
                              scale=.1,
                              frameSize=buttonSize,
                              command=self.moveFormation)
        button.reparentTo(frame)
        button.setPos(Vec3(0, 0, -6 * buttonDistance))

        self.moveX = DirectEntry(text="",
                                 initialText="0",
                                 scale=.1,
                                 frameSize=entrySize)
        self.moveX.reparentTo(frame)
        self.moveX.setPos(Vec3(0.5, 0, -6 * buttonDistance))

        self.moveY = DirectEntry(text="",
                                 initialText="0",
                                 scale=.1,
                                 frameSize=entrySize)
        self.moveY.reparentTo(frame)
        self.moveY.setPos(Vec3(0.75, 0, -6 * buttonDistance))

        self.moveZ = DirectEntry(text="",
                                 initialText="0",
                                 scale=.1,
                                 frameSize=entrySize)
        self.moveZ.reparentTo(frame)
        self.moveZ.setPos(Vec3(1, 0, -6 * buttonDistance))

        self.rotSpeed = DirectEntry(text="",
                                    initialText="3",
                                    scale=.1,
                                    frameSize=entrySize)
        self.rotSpeed.reparentTo(frame)
        self.rotSpeed.setPos(Vec3(0.5, 0, -5 * buttonDistance))

        # initialize an UI element with all available formations
        loadFormationSelectionFrame(self)

    def startLandAll(self, button):
        if not self.isStarted:
            self.isStarted = True
            button["text"] = "Land"
            print("starting all")
            for drone in self.drones:
                pos = drone.getPos()
                drone.setTarget(target=Vec3(pos[0], pos[1], 1))
        else:
            self.isStarted = False
            button["text"] = "Start"
            print("landing all")
            for drone in self.drones:
                pos = drone.getPos()
                drone.setTarget(target=Vec3(pos[0], pos[1], 0))

    def returnToWaitingPosition(self):
        """Makes all drones hover above their starting position. Useful to make the drones land just where they started."""
        if not self.isStarted:
            print("can't return to waiting position, drones are not started")
            return
        print("returning to waiting positions")
        for drone in self.drones:
            drone.setTarget(drone.waitingPosition)

    def setRandomTargets(self):
        """Set random targets for all drones."""
        if not self.isStarted:
            print("can't set random targets, drones are not started")
            return
        print("setting random targets")
        for drone in self.drones:
            drone.setRandomTarget()

    def stopAll(self):
        """Stops all drones and makes them hover where they are."""
        if not self.isStarted:
            print("can't stop drones, drones are not started")
            return
        print("stopping drones")
        for drone in self.drones:
            drone.setTarget(target=drone.getPos())

    def toggleConnections(self, button):
        """Connects/Disconnects the virtual drones to/from the real drones."""
        # connect drones
        if not self.isConnected:
            self.isConnected = True
            button["text"] = "Disconnect"
            print("initializing drivers")
            cflib.crtp.init_drivers(enable_debug_driver=False)
            print("connecting drones")
            for drone in self.drones:
                drone.connect()
            # time.sleep(5)  # wait a moment so that the position estimator reports a consisten position
        # disconnect drones
        else:
            self.isConnected = False
            button["text"] = "Connect"
            print("disconnecting drones")
            for drone in self.drones:
                if drone.isConnected:
                    drone.disconnect()

    def applyFormation(self, formation):
        """Applies the supplied formation to the drones."""
        if not self.isStarted:
            print("Can't apply formation, drones are not started")
            return

        # name = formation[0]
        dronePositions = formation[1]
        requiredDrones = len(dronePositions)

        availableDrones = self.drones.__len__()
        maxNumber = availableDrones
        if requiredDrones > availableDrones:
            print(
                "The formation contains {0} points but there are only {1} available drones"
                .format(requiredDrones, availableDrones))

        if requiredDrones < availableDrones:
            print(
                "The formation contains {0} points but there are {1} available drones, some drones will remain stationary"
                .format(requiredDrones, availableDrones))
            maxNumber = requiredDrones

        # print("applying {} formation".format(formation[0]))
        for i in range(0, maxNumber):
            self.drones[i].setNewRandVec()
            self.drones[i].setTarget(
                Vec3(dronePositions[i, 0], dronePositions[i, 1],
                     dronePositions[i, 2]))

        self.currentFormation = formation

    def moveFormation(self):
        if (self.currentFormation == 0):
            return
        newFormation = self.currentFormation
        newFormation[1] += [
            float(self.moveX.get()),
            float(self.moveY.get()),
            float(self.moveZ.get())
        ]
        self.applyFormation(newFormation)

    def toggleRotation(self):
        if (self.currentFormation == 0):
            return
        if not self.isRotating:
            self.isRotating = True
            self.base.taskMgr.doMethodLater(0, self.rotateFormationTask,
                                            "RotateDrones")
        else:
            self.isRotating = False
            self.base.taskMgr.remove("RotateDrones")

    def rotateFormationTask(self, task):
        task.delayTime = 0.1
        newFormation = self.currentFormation
        speed = 2
        try:
            speed = float(self.rotSpeed.get())
        except:
            speed = 2
        r = R.from_euler('xyz', [0, 0, speed], degrees=True)
        newFormation[1] = r.apply(newFormation[1])
        self.applyFormation(newFormation)
        return task.again

    def getRandomRoomCoordinate(self) -> Vec3:
        """Returns random 3D coordinates withing the confines of the room."""
        newX = random.uniform(-self.roomSize.x / 2, self.roomSize.x / 2)
        newY = random.uniform(-self.roomSize.y / 2, self.roomSize.y / 2)
        newZ = random.uniform(0 + 0.3, self.roomSize.z)
        return Vec3(newX, newY, newZ)

    def getAllPositions(self):
        """Returns a list of the positions of all drones. Usefull when recording their paths for later."""
        lst = []
        for drone in self.drones:
            pos = drone.getPos()
            lst.append([pos.x, pos.y, pos.z])
        return lst

    def getAllVelocities(self):
        """Returns a list of the velocities of all drones. Usefull when recording their paths for later."""
        lst = []
        for drone in self.drones:
            vel = drone.getVel()
            lst.append([vel.x, vel.y, vel.z])
        return lst