예제 #1
0
class DronePosition(object):
    def __init__(self, image):

        self.pid = PIDController()
        self.process = ProcessVideo()

        #take input as bgr image, given orange is visible, will command to hover ontop of it
        def HoverOnCheckpoint(self, image):

            # calculating cx,cy,xspeed,yspeed
            orange_image = self.process.DetectColor(image, 'orange')
            self.cx, self.cy = self.process.CenterofMass(orange_image)
            self.pid.UpdateDeltaTime()
            self.pid.SetPoint(orang_image)
            self.pid.UpdateError(self.cx, self.cy)
            self.pid.SetPIDTerm()
            xspeed, yspeed = self.pid.GetPIDValues()
            self.pid.DrawArrow(orange_image, xspeed, yspeed)

            return xspeed, yspeed

        def OrienttoLine(self, image):

            orange_image = self.process.DetectColor(image, 'orange')
            self.cx, self.cy = self.process.CenterofMass(orange_image)
            blue_image = self.process.DetectColor(image, 'blue')
            angle = self.process.ShowLine(blue_image)
            yawspeed = self.process.LineOrientation(blue_image, angle, 5)

            return yawspeed

        def OrienttoObject(self, image):

            orange_image = self.process.DetectColor(image, 'orange')
            self.cx, self.cy = self.process.CenterofMass(orange_image)
            green_image = self.process.DetectColor(image, 'green')
            angle = self.process.ShowLine(green_image)
            yawspeed = self.process.ObjectOrientation(green_image, angle, 5)

            return yawspeed
예제 #2
0
class OrientLineDirective(AbstractDroneDirective):

    # orientation:
    #   > either "VERTICAL" or "PERPENDICULAR";
    #     algorithm will orient drone vertically or perpendicular to the line respectively
    # lineColor:
    #   > color of the line to orient to
    # platformColor:
    #   > color of the platform to orient to
    # hoverAltitude:
    #   > how high to hover over the platform
    def __init__(self,
                 orientation,
                 lineColor,
                 platformColor,
                 hoverAltitude,
                 heightTolerance=50,
                 yOffset=0,
                 ySizeOffset=0):

        if orientation != "PARALLEL" and orientation != "PERPENDICULAR":
            raise Exception("Orientation not recognized.")
        else:
            self.orientation = orientation

        self.lineColor = lineColor
        self.platformColor = platformColor
        self.hoverAltitude = hoverAltitude
        self.processVideo = ProcessVideo()
        self.prevCenter = None
        self.forceCenter = None
        self.prevAngle = None
        self.heightTolerance = heightTolerance
        self.yOffset = yOffset
        self.ySizeOffset = ySizeOffset

    # Given the image and navdata of the drone, returns the following in order:
    #
    # A directive status int:
    #   0 if algorithm is still running and drone isn't oriented yet
    #   1 if algorithm is finished and drone is now oriented
    #
    # A tuple of (xspeed, yspeed, yawspeed, zspeed):
    #   indicating the next instructions to fly the drone
    #
    # An image reflecting what is being done as part of the algorithm
    def RetrieveNextInstruction(self, image, navdata):

        self.moveTime = 0.17
        #self.moveTime=0.23
        self.waitTime = 0.1

        segLineImage = self.processVideo.DetectColor(image, self.lineColor)

        cx, cy = navdata["center"][1][0], navdata["center"][1][1]

        if cx != None and cy != None:
            cv2.circle(segLineImage, (cx, cy), 6, (255, 255, 255), -1)

        centers = navdata["allCenters"][1]

        if self.forceCenter != None:
            self.forceCenter = None

        # when directive first starts, it latches onto the first correct orange platform it sees
        if self.prevCenter == None:

            rospy.logwarn("FINDING INITAL CENTER---")

            if cx != None and cy != None:
                self.prevCenter = (cx, cy)

            # pick the rightmost center
            rightmostCenter = centers[0]
            if self.orientation == "PARALLEL":
                for i in range(len(centers)):
                    if centers[i][0] > rightmostCenter[0]:
                        rightmostCenter = centers[i]
                self.forceCenter = rightmostCenter
            else:
                # pick the center that is closest to the most vertical pink line
                # finding most vertical line
                objectLineImg = self.processVideo.DetectColor(image, "pink")
                objectLines, objectLineImg = self.processVideo.MultiShowLine(
                    objectLineImg, sort=False)
                mostVertical = None
                rospy.logwarn(" All pink lines: ")
                for line in objectLines:
                    if line != None:
                        rospy.logwarn("@: " + str(line[1]) + ", " +
                                      str(line[0]) + " degrees")
                        if mostVertical == None or (
                            (abs(90 - line[0]) < abs(90 - mostVertical[0]))
                                and line[4] > 30):
                            #if ( mostHorizontal == None or
                            #( min(mostHorizontal[0], 180 - mostHorizontal[0] ) > (min(line[0], 180 - line[0] ) )
                            #and line[4] > 30 ) ):
                            #mostHorizontal = line
                            mostVertical = line

                rospy.logwarn("Found most vertical pink line @: " +
                              str(mostVertical[1]) + ", with angle " +
                              str(mostVertical[0]))
                """
                # finding center closest to the left endpoint of that vertical line
                if mostHorizontal[2][0] < mostHorizontal[3][0]:
                    leftEndpoint = mostHorizontal[2]
                else:
                    leftEndpoint = mostHorizontal[3]
                """

                correctCenter = centers[0]

                rospy.logwarn("All centers: ")
                for i in range(len(centers)):
                    """
                    correctEndpointDist = math.sqrt( math.pow((correctCenter[1] - leftEndpoint[1]),2) 
                    + math.pow((correctCenter[0] - leftEndpoint[0]),2 ) ) 

                    currEndpointDist = math.sqrt( math.pow((centers[i][1] - leftEndpoint[1]),2) 
                    + math.pow((centers[i][0] - leftEndpoint[0]),2 ) ) 
                    
                    if currEndpointDist < correctEndpointDist:
                        correctCenter = centers[i]
                    """
                    rospy.logwarn("@: " + str(centers[i]))
                    if abs(mostVertical[1][0] -
                           centers[i][0]) < abs(mostVertical[1][0] -
                                                correctCenter[0]):
                        correctCenter = centers[i]

                self.forceCenter = correctCenter
                rospy.logwarn("Closest center to vertical pink line is @: " +
                              str(correctCenter))

        elif cx != None and cy != None:

            # checking if curr center is consistent with previous one
            centerDist = math.sqrt(
                math.pow((self.prevCenter[1] - cy), 2) +
                math.pow((self.prevCenter[0] - cx), 2))
            if centerDist > 225:
                rospy.logwarn("ERROR: ORIGINAL CENTER LOST, showing all " +
                              str(len(centers)))
                for i in range(len(centers)):
                    cv2.circle(segLineImage, centers[i], 6, (255, 0, 0), -1)
                if cx != None and cy != None:
                    cv2.circle(segLineImage, (cx, cy), 10, (255, 255, 255), -1)

                cx = self.prevCenter[0]
                cy = self.prevCenter[1]
                cv2.circle(segLineImage, (cx, cy), 10, (0, 0, 255), 4)
                directiveStatus = -1
                return directiveStatus, (0, 0, 0,
                                         0), segLineImage, (cx, cy), 0, 0, None
            else:
                self.prevCenter = (cx, cy)

        if self.orientation == "PARALLEL":
            lines, segLineImage = self.processVideo.MultiShowLine(segLineImage,
                                                                  sort=False)

            # pick the pink line closest to the hover platform
            angle = None
            closest = None
            closestDist = None
            for line in lines:
                if cx != None:

                    dist = math.sqrt(
                        math.pow((line[1][1] - cy), 2) +
                        math.pow((line[1][0] - cx), 2))

                    if (line != None and line[4] > 30
                            and (closest == None or (dist < closestDist))):

                        closest = line
                        angle = closest[0]
                        closestDist = dist

            if closest != None:
                cv2.circle(segLineImage, closest[1], 15, (0, 255, 0), -1)
                for line in lines:
                    if line != None and line[1] != closest[1]:
                        cv2.circle(segLineImage, line[1], 15, (0, 0, 255), -1)

            #converting angle
            if angle != None:

                # checking if previous angle is consistent with current one
                if self.prevAngle == None or min(
                        abs(self.prevAngle - angle),
                        180 - abs(self.prevAngle - angle)) < 17:
                    self.prevAngle = angle
                else:
                    rospy.logwarn(
                        "ERROR: ORIGINAL CENTER LOST; angle mismatch. Before: "
                        + str(self.prevAngle) + " Now: " + str(angle))
                    directiveStatus = -1
                    return directiveStatus, (0, 0, 0, 0), segLineImage, ((
                        cx, cy), self.prevAngle), 0, 0, None

                if angle == 90:
                    angle = 0
                elif angle < 90:
                    angle = angle + 90
                else:
                    angle = angle - 90

            yawspeed = self.processVideo.ObjectOrientation(segLineImage,
                                                           angle,
                                                           4,
                                                           yawspeed=0.50)
            #.42
            if yawspeed != None:
                yawspeed = -1 * yawspeed
            xWindowSize = 60
            yWindowSize = 105 + self.ySizeOffset
            xWindowOffset = 0
            yWindowOffset = self.yOffset
            altLowerTolerance = self.heightTolerance
            altUpperTolerance = self.heightTolerance - 15
            # defines window to make the drone focus on moving away from the edges and back into
            # the center; yaw will be turned off
            xReturnSize = xWindowSize + 210
            yReturnSize = yWindowSize + 110

        elif self.orientation == "PERPENDICULAR":

            kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))
            segLineImage = cv2.morphologyEx(segLineImage, cv2.MORPH_OPEN,
                                            kernel)
            lines, segLineImage = self.processVideo.MultiShowLine(segLineImage,
                                                                  sort=False)

            # pick the blue line closest to the hover platform, AND is right of the hover platform
            angle = None
            closest = None
            for line in lines:
                if (line != None and cx != None and line[1][0] >= cx and
                    (closest == None
                     or abs(cx - line[1][0]) < abs(cx - closest[1][0]))):
                    closest = line
                    angle = closest[0]

            if closest != None:
                cv2.circle(segLineImage, closest[1], 15, (0, 255, 0), -1)
                for line in lines:
                    if line != None and line[1] != closest[1]:
                        cv2.circle(segLineImage, line[1], 15, (0, 0, 255), -1)

            #converting angle
            if angle != None:
                # checking if previous angle is consistent with current one
                if self.prevAngle == None or min(
                        abs(self.prevAngle - angle),
                        180 - abs(self.prevAngle - angle)) < 27:
                    self.prevAngle = angle
                else:
                    rospy.logwarn(
                        "ERROR: ORIGINAL CENTER LOST; angle mismatch. Before: "
                        + str(self.prevAngle) + " Now: " + str(angle))
                    directiveStatus = -1
                    return directiveStatus, (0, 0, 0, 0), segLineImage, ((
                        cx, cy), self.prevAngle), 0, 0, None

                if angle == 90:
                    angle = 0
                elif angle < 90:
                    angle = angle + 90
                else:
                    angle = angle - 90

            yawspeed = self.processVideo.LineOrientation(segLineImage,
                                                         angle,
                                                         9,
                                                         yawspeed=0.50)
            if yawspeed != None:
                yawspeed = -1 * yawspeed
            xWindowSize = 295
            yWindowSize = 70
            xWindowOffset = 0
            yWindowOffset = 0
            altLowerTolerance = 200
            altUpperTolerance = 250
            # defines window to make the drone focus on moving away from the edges and back into
            # the center; yaw will be turned off
            xReturnSize = xWindowSize
            yReturnSize = yWindowSize

        numRows, numCols, _ = image.shape
        centerx = numCols / 2 - xWindowOffset
        centery = numRows / 2 - yWindowOffset

        xspeed, yspeed, zspeed = self.processVideo.ApproximateSpeed(
            segLineImage,
            cx,
            cy,
            centerx,
            centery,
            navdata["SVCLAltitude"][1],
            self.hoverAltitude,
            xtolerance=xWindowSize,
            ytolerance=yWindowSize,
            ztolerance=(altLowerTolerance, altUpperTolerance),
            xOffset=xWindowOffset,
            yOffset=yWindowOffset)

        # box defines when the directive is finished
        xLower = (numCols / 2) - xReturnSize
        yLower = (numRows / 2) - yReturnSize
        xUpper = (numCols / 2) + xReturnSize
        yUpper = (numRows / 2) + yReturnSize

        # perpendicular can disregard height
        #if self.orientation == "PERPENDICULAR":
        #    zspeed = 0

        if (yawspeed == 0 and xspeed == 0 and yspeed == 0 and zspeed == 0
                and cx != None and cy != None):

            rospy.logwarn("Oriented " + self.orientation + " to " +
                          self.lineColor + " line")
            directiveStatus = 1

        elif cx == None or cy == None:

            rospy.logwarn("*** ERROR: Lost " + self.platformColor +
                          " platform ***")
            directiveStatus = -1

        else:

            # If drone is still trying to align, it adapts to one of three algorithms:

            # Drone will just go back near the center if: 1) no line is detcted, or 2)
            # the drone is not "near" the center as defined by a bounding box
            # No turning or altitude change applied
            if yawspeed == None or (cx > xUpper or cx < xLower or cy > yUpper
                                    or cy < yLower):
                cv2.rectangle(segLineImage, (xLower, yLower), (xUpper, yUpper),
                              (0, 0, 255), 2)
                rospy.logwarn("Too far out; only MOVING drone back to center")
                yawspeed = 0
                zspeed = zspeed * 0.2

            # if drone isn't perpendicular yet and is "near" the center (defined by a box),
            # just turn the drone; no need move drone
            elif yawspeed != 0:
                rospy.logwarn("Only TURNING drone. Yaw speed = " +
                              str(yawspeed))
                self.moveTime = 3.5
                xspeed = 0
                yspeed = 0
                zspeed = zspeed * 0.45

            # if the drone is aligned to the line and is near the center,
            # keep moving it to the center and adjusting the height until the
            # directive is finished
            else:
                rospy.logwarn("Curr Altitude = " +
                              str(int(navdata["SVCLAltitude"][1])) +
                              " mm; Goal = [ " +
                              str(self.hoverAltitude - altLowerTolerance) +
                              " mm, " +
                              str(self.hoverAltitude + altUpperTolerance) +
                              " mm ].")

            directiveStatus = 0

        return directiveStatus, (
            xspeed, yspeed, yawspeed, zspeed), segLineImage, (
                (cx, cy),
                self.prevAngle), self.moveTime, self.waitTime, self.forceCenter

    def Finished(self):
        center = self.prevCenter
        self.prevAngle = None
        self.prevCenter = None
        self.forceCenter = None
        return center

    def OnErrorReturn(self, returnData):
        # set previous center to what was found in the error algorithm
        rospy.logwarn("ORIENT LINE ON ERROR RETURN***")
        self.prevCenter = returnData
        self.prevAngle == None
예제 #3
0
class PIDOrientLineDirective(AbstractDroneDirective):

    # orientation:
    #   > either "VERTICAL" or "PERPENDICULAR";
    #     algorithm will orient drone vertically or perpendicular to the line respectively
    # lineColor:
    #   > color of the line to orient to
    # platformColor:
    #   > color of the platform to orient to
    # settingsPath:
    #   > Path for getting PID settings
    # hoverAltitude:
    #   > how high to hover over the platform
    def __init__(self, orientation, lineColor, platformColor, settingsPath):

        if orientation != "PARALLEL" and orientation != "PERPENDICULAR":
            raise Exception("Orientation not recognized.")
        else:
            self.orientation = orientation
        self.lineColor = lineColor
        self.platformColor = platformColor

        self.processVideo = ProcessVideo()
        P, I, D = self.GetSettings(settingsPath)
        self.pid = PIDController(360, 640, P, I, D)
        self.moveTime = 0.2
        self.waitTime = 0.1

    def GetSettings(self, settingsPath):
        # read a text file as a list of lines
        # find the last line, change to a file you have
        fileHandle = open(settingsPath, 'r')
        last = fileHandle.readlines()
        fileHandle.close()

        last = str(last[len(last) - 1]).split()
        p, i, d = [float(x) for x in (last)]

        return p, i, d

    # Given the image and navdata of the drone, returns the following in order:
    #
    # A directive status int:
    #   0 if algorithm is still running and drone isn't oriented yet
    #   1 if algorithm is finished and drone is now oriented
    #
    # A tuple of (xspeed, yspeed, yawspeed, zspeed):
    #   indicating the next instructions to fly the drone
    #
    # An image reflecting what is being done as part of the algorithm
    def RetrieveNextInstruction(self, image, navdata):

        segLineImage = self.processVideo.DetectColor(image, self.lineColor)

        cx, cy = navdata["center"][1][0], navdata["center"][1][1]
        altitude = navdata["SVCLAltitude"][1]

        #draws center of circle on image
        self.processVideo.DrawCircle(segLineImage, (cx, cy))

        self.pid.UpdateDeltaTime()
        self.pid.UpdateError(cx, cy, altitude)
        self.pid.SetPIDTerms()
        xspeed, yspeed = self.pid.GetPIDValues()

        if self.orientation == "PARALLEL":

            angle = self.processVideo.ShowLine(segLineImage,
                                               lowerAngleBound=0,
                                               upperAngleBound=70,
                                               secondBounds=(110, 180),
                                               thresh=35)
            yawspeed = self.processVideo.ObjectOrientation(segLineImage,
                                                           angle,
                                                           5,
                                                           yawspeed=0.5)
            xWindowSize = 50
            yWindowSize = 50

        elif self.orientation == "PERPENDICULAR":

            angle = self.processVideo.ShowLine(segLineImage,
                                               lowerAngleBound=30,
                                               upperAngleBound=125,
                                               thresh=15)
            yawspeed = self.processVideo.LineOrientation(segLineImage,
                                                         angle,
                                                         5,
                                                         yawspeed=0.5)
            xWindowSize = 180
            yWindowSize = 70

        numRows, numCols, _ = image.shape
        centerx = numCols / 2
        centery = numRows / 2

        # box defines when the directive is finished
        xLower = centerx - xWindowSize
        yLower = centery - yWindowSize
        xUpper = centerx + xWindowSize
        yUpper = centery + yWindowSize
        cv2.rectangle(segLineImage, (xLower, yLower), (xUpper, yUpper),
                      (255, 255, 255), 3)

        if (yawspeed == 0 and cx != None and cy != None and cx < xUpper
                and cx > xLower and cy < yUpper and cy > yLower):

            rospy.logwarn("Oriented " + self.orientation + " to " +
                          self.lineColor + " line")
            directiveStatus = 1

        elif cx == None or cy == None:

            rospy.logwarn("*** ERROR: Lost " + self.platformColor +
                          " platform ***")
            directiveStatus = -1

        else:

            # If drone is still trying to align, it adapts to one of three algorithms:

            # if this frame failed to detect a line, go towards platform
            # without turning in hopes that the next frames will detect one again
            if yawspeed == None:
                #rospy.logwarn("No line detected")
                yawspeed = 0

            # if drone is not "near" the center defined by a box, just focus on moving drone back;
            # no turning
            elif self.orientation == "PERPENDICULAR" and (
                    cx > xUpper or cx < xLower or cy > yUpper or cy < yLower):
                cv2.rectangle(segLineImage, (xLower, yLower), (xUpper, yUpper),
                              (0, 0, 255), 3)
                #rospy.logwarn("Only MOVING drone. x speed = " + str(xspeed) + "; y speed = " + str(yspeed))
                rospy.logwarn("Only MOVING drone")
                self.moveTime = 0.1
                self.waitTime = 0.01
                yawspeed = 0

            # if drone isn't perpendicular yet and is "near" the center (defined by a box),
            # just turn the drone; no need move drone
            elif yawspeed != 0:
                #rospy.logwarn("Only TURNING drone. yaw speed = " + str(yawspeed))
                rospy.logwarn("Only TURNING drone")
                self.moveTime = 0.2
                self.waitTime = 0.1
                xspeed = 0
                yspeed = 0

            #else:

            #   rospy.logwarn("Only MOVING drone")
            #rospy.logwarn("Only MOVING drone. x speed = " + str(xspeed) + "; y speed = " + str(yspeed))

            directiveStatus = 0

        return directiveStatus, (xspeed, yspeed, yawspeed, 0), segLineImage, (
            cx, cy), self.moveTime, self.waitTime, None

    # This method is called by the state machine when it considers this directive finished
    def Finished(self):
        rospy.logwarn("***** Resetting PID Values *****")
        self.pid.ResetPID()
예제 #4
0
class FollowLineDirective(AbstractDroneDirective):

    # sets up this directive
    # lineColor: color of the line to follow
    def __init__(self, lineColor, speed=0.4):

        self.lineColor = lineColor
        self.speed = speed
        self.processVideo = ProcessVideo()
        self.moveTime = 0.45
        self.waitTime = 0.1
        self.prevAngle = None
        self.prevAngleCount = 0
        self.prevAngleCountMax = 185

    # Given the image and navdata of the drone, returns the following in order:
    #
    # A directive status int:
    #   0 if algorithm is still running and drone is still following line
    #   1 if algorithm is finished and has finished following line
    #
    # A tuple of (xspeed, yspeed, yawspeed, zspeed):
    #   indicating the next instructions to fly the drone
    #
    # An image reflecting what is being done as part of the algorithm
    def RetrieveNextInstruction(self, image, navdata):

        segLineImage = self.processVideo.DetectColor(image, self.lineColor)
        platforms = navdata["allCenters"][1]
        lines, image = self.processVideo.MultiShowLine(segLineImage)

        if lines[0] != None:
            cv2.circle(image, lines[0][1], 15, (0, 0, 255), -1)
        if lines[1] != None:
            cv2.circle(image, lines[1][1], 15, (0, 255, 0), -1)
        if lines[2] != None:
            cv2.circle(image, lines[2][1], 15, (255, 0, 0), -1)

        linesVisible = (lines[0] != None) + (lines[1] != None) + (lines[2] !=
                                                                  None)

        if linesVisible == 0:
            rospy.logwarn(" *** ERROR: Lost " + self.lineColor + " line *** ")
            return -1, (0, 0, 0, 0), segLineImage, (None, None), 0, 0, None

        cx = lines[1][1][0]
        cy = lines[1][1][1]
        _, yspeed, _ = self.processVideo.ApproximateSpeed(
            segLineImage,
            cx,
            cy,
            None,
            None,
            navdata["SVCLAltitude"][1],
            0,
            xtolerance=80,
            ytolerance=95)

        newCenter = None
        thresh = 15

        # Checking if angle is consistent with before
        if (self.prevAngle == None
                or abs(self.prevAngle - lines[1][0]) < thresh
                or abs(self.prevAngle - lines[1][0]) > (180 - thresh)):

            self.prevAngle = lines[1][0]
            self.prevAngleCount = 0
            directiveStatus = 0

            # checking finish conditions
            # alternate way to finish
            xWindowSize = 200
            yWindowSize = 120
            xLower = 320 - xWindowSize
            yLower = 180 - yWindowSize
            xUpper = 320 + xWindowSize
            yUpper = 180 + yWindowSize

            foundRightPlatform = False
            tolerance = 15
            for platform in platforms:
                if (linesVisible > 1 and lines[1] != None
                        and platform[0] > lines[1][1][0]
                        and min(abs(lines[1][0] - 180),
                                180 - abs(lines[1][0] - 180)) < 16
                        and platform[0] < xUpper and platform[0] > xLower
                        and platform[1] < yUpper and platform[1] > yLower):
                    cv2.rectangle(image, (xLower, yLower), (xUpper, yUpper),
                                  (255, 255, 255), 4)
                    foundRightPlatform = True
                    newCenter = platform

            # in order to be considered "finished", there must be 2 lines,
            # one which is horizontal and one that is less than 90 degrees.
            # The horizontal line must be far enough left.
            if (foundRightPlatform or
                (len(platforms) == 1 and yspeed == 0 and lines[1] != None
                 and lines[2] != None and
                 ((lines[1][0] < (0 + tolerance)) or (lines[1][0]) >
                  (180 - tolerance)) and lines[2][1][0] < int(640 * 0.9))):

                xspeed = 0
                yspeed = 0
                yawspeed = 0
                directiveStatus = 1
                rospy.logwarn("Finished following line")
                return directiveStatus, (xspeed, yspeed, yawspeed, 0), image, (
                    (cx, cy),
                    self.prevAngle), self.moveTime, self.waitTime, newCenter

        else:

            # only uses the angle if it is similar to the last one. If it is too different, algorithm
            # uses the previous angle for a time until the timer is up, as a buffer against a random large angle change

            rospy.logwarn(
                "Large sudden change in angle -- using old angle of " +
                str(self.prevAngle) + " instead of " + str(lines[1][0]))
            directiveStatus = -1

        xspeed = -self.speed

        # converting
        line1Angle = self.prevAngle
        if line1Angle == 90:
            line1Angle = 0
        elif line1Angle < 90:
            line1Angle = line1Angle + 90
        else:
            line1Angle = line1Angle - 90

        yawspeed = self.processVideo.LineOrientation(segLineImage,
                                                     line1Angle,
                                                     8,
                                                     yawspeed=0.45)

        # If drone is still trying follow the line, it adapts to one of three algorithms:

        # Drone will just go back near the center if the drone is not "near" the
        # center as defined by a bounding box.
        # No turning or horizontal movement is applied.
        if yspeed != 0:
            rospy.logwarn("Moving blue line back to center")
            self.moveTime = 0.2
            self.waitTime = 0.1
            xspeed = 0
            yawspeed = 0

        # If drone is near the center but angle is off, it fixes the angle.
        # Drone does not move forward.
        elif yawspeed != 0:

            yawspeed = -yawspeed

            direction = "LEFT"
            if yawspeed < 0:
                direction = "RIGHT"

            rospy.logwarn("Turning the drone horizontal " + direction +
                          ",  yaw = " + str(yawspeed))
            self.moveTime = 1
            self.waitTime = 0.1
            xspeed = 0

        else:
            rospy.logwarn("Drone just going forward")
            self.moveTime = 0.9
            self.waitTime = 0.1

        return directiveStatus, (xspeed, yspeed, yawspeed, 0), image, ((
            cx, cy), self.prevAngle), self.moveTime, self.waitTime, newCenter

    def Finished(self):
        self.prevAngle = None
        self.prevAngleCount = 0
        return None