Esempio n. 1
0
def executeRotateAndDrive(commandPayload):
    maxVelocity = int(commandPayload[0])
    pivotTurnSpeed = int(commandPayload[1])
    optionByte1 = int(commandPayload[2])
    optionByte2 = int(commandPayload[3])
    piOptionByte1 = int(commandPayload[4])
    rotationAngle = int(commandPayload[5])
    distance = int(commandPayload[6])

    waypoints = []

    if globals.currentCommandPhase == 0:
        globals.currentCommand = enums.PI_CMD_ROTATE_AND_DRIVE
        globals.currentCommandPhase = 1
        globals.currentCommandPayload = commandPayload

        waypoint = (rotationAngle, 0)
        waypoints.append(waypoint)

        msg = ('R&D P1: Rotating [pivotSpeed: %d, opt1: %2X, opt2: %2X]' %
               (pivotTurnSpeed, optionByte1, optionByte2))
    elif globals.currentCommandPhase == 1:
        globals.currentCommand = 0
        globals.currentCommandPayload = 0

        if distance:
            targetX = globals.currentX + (distance *
                                          math.cos(globals.currentHeading))
            targetY = globals.currentY + (distance *
                                          math.sin(globals.currentHeading))

            waypoint = (int(targetX), int(targetY))
            waypoints.append(waypoint)
            optionByte2 = 0  # this carries the rotate command, need to switch back to waypoint transit

            msg = (
                'R&D P2: Driving %d cm from (%d,%d) to (%d,%d) [maxVelocity: %d]'
                % (distance, globals.currentX, globals.currentY, targetX,
                   targetY, maxVelocity))
        else:
            return (True, '')  # no drive phase
    else:
        globals.currentCommand = 0
        globals.currentCommandPhase = 0
        return (False, 'Unknown phase')

    print(msg)
    udp.logToBotlab(msg, False)

    transmitSegments = i2c.buildTransmitSegments(waypoints, maxVelocity,
                                                 pivotTurnSpeed, optionByte1,
                                                 optionByte2)
    i2c.registerTransmitSegments(transmitSegments)

    return (True, '')
Esempio n. 2
0
def executeSetBotOption(commandPayload):
    maxVelocity = int(commandPayload[0])
    pivotTurnSpeed = int(commandPayload[1])
    optionByte1 = int(commandPayload[2])
    optionByte2 = int(commandPayload[3])
    piOptionByte1 = int(commandPayload[4])

    packedOptions = commandPayload[5:]
    waypoints = []

    if len(packedOptions) % 2 != 0:
        return (False, 'Received invalid packed options from botLab')

    packedOptionCount = int(len(packedOptions) / 2)

    print('Received %d packed options [%s]' %
          (packedOptionCount, packedOptions))

    for i in range(packedOptionCount):
        packedOption = (int(packedOptions[i * 2]),
                        int(packedOptions[(i * 2) + 1]))
        waypoints.append(packedOption)

    msg = ''

    if optionByte1 == enums.BOT_OPTION_CALIBRATE:
        msg = ('Executing bot calibration [pivotSpeed: %d]' % (pivotTurnSpeed))
    elif optionByte1 == enums.BOT_OPTION_RESET_TO_ORIGIN:
        msg = 'Reset to origin'
        globals.currentX = 0
        globals.currentY = 0
        globals.currentHeading = 0
    elif optionByte1 == enums.BOT_OPTION_SET_PID_PARAMETERS:
        msg = 'Updated PID parameters'
    else:
        return (False, 'Unknown bot option')

    print(msg)
    udp.logToBotlab(msg, False)

    transmitSegments = i2c.buildTransmitSegments(waypoints, maxVelocity,
                                                 pivotTurnSpeed, optionByte1,
                                                 optionByte2)
    i2c.registerTransmitSegments(transmitSegments)

    return (True, '')
Esempio n. 3
0
def executeTransit(commandPayload):
    maxVelocity = int(commandPayload[0])
    pivotTurnSpeed = int(commandPayload[1])
    optionByte1 = int(commandPayload[2])
    optionByte2 = int(commandPayload[3])
    piOptionByte1 = int(commandPayload[4])

    globals.followMeWaypoints = []
    globals.followMeMaxVelocity = maxVelocity
    globals.followMePivotTurnSpeed = pivotTurnSpeed

    points = commandPayload[5:]
    waypoints = []

    if len(points) % 2 != 0:
        return (False, 'Received invalid waypoint instructions from botLab')

    waypointCount = int(len(points) / 2)

    print('Received %d waypoints [%s]' % (waypointCount, points))

    for i in range(waypointCount):
        waypoint = (int(points[i * 2]), int(points[(i * 2) + 1]))
        waypoints.append(waypoint)

    if piOptionByte1 & enums.PI_OPTION_FOLLOW_ME_MODE:
        globals.followMe = True
    else:
        globals.followMe = False

    msg = (
        'Transit between %d waypoints [maxVelocity: %d, pivotSpeed: %d, opt1: %2X, opt2: %2X, piOpt1: %2X]'
        % (waypointCount, maxVelocity, pivotTurnSpeed, optionByte1,
           optionByte2, piOptionByte1))
    print(msg)
    udp.logToBotlab(msg, False)

    globals.currentCommand = enums.PI_CMD_TRANSIT_WAYPOINTS

    transmitSegments = i2c.buildTransmitSegments(waypoints, maxVelocity,
                                                 pivotTurnSpeed, optionByte1,
                                                 optionByte2)
    i2c.registerTransmitSegments(transmitSegments)

    return (True, '')
Esempio n. 4
0
def detectRedBox(currentX, currentY, currentHeading, uploadSnapshots):
    global lowerColourRange
    global upperColourRange
    global cameraDimX

    if lowerColourRange == None or upperColourRange == None:
        msg = 'Camera not calibrated'
        print(msg)
        udp.logToBotlab(msg, False)
        return (False, 0, 0)

    camera = getCamera()

    timestamp = time.time()
    imageName = '%s/%u.jpg' % (config.imagePath, timestamp)

    camera.capture(imageName, resize=(320, 240))

    bgrImg = cv2.imread(imageName)
    hsvImg = cv2.cvtColor(bgrImg, cv2.COLOR_BGR2HSV)

    (foundObject, x, y, width, height,
     aspectRatio) = detectTrackedObject(hsvImg, bgrImg, lowerColourRange,
                                        upperColourRange)

    if uploadSnapshots:
        labelledImageName = '%s/%u-labelled.jpg' % (config.imagePath,
                                                    timestamp)
        cv2.imwrite(labelledImageName, bgrImg)
        uploadSnapshot(labelledImageName)

    (targetX, targetY) = (0, 0)

    if foundObject:
        (targetX,
         targetY) = calculatePositionOfTrackedObject(currentX, currentY,
                                                     currentHeading, x, y,
                                                     width, cameraDimX)

    return (foundObject, targetX, targetY)
Esempio n. 5
0
def calibrateCameraUntilObjectFound(acceptableHueRange, uploadSnapshots):
    global lowerColourRange
    global upperColourRange
    global cameraDimX

    if acceptableHueRange < 0:
        acceptableHueRange = 40

    camera = getCamera()
    foundObject = False

    while not foundObject:
        timestamp = time.time()
        imageName = '%s/%u.jpg' % (config.imagePath, timestamp)
        camera.capture(imageName, resize=(320, 240))

        bgrImg = cv2.imread(imageName)
        hsvImg = cv2.cvtColor(bgrImg, cv2.COLOR_BGR2HSV)

        (cameraDimX, cameraDimY, averageHue, lowerColourRange,
         upperColourRange) = calibrateCamera(hsvImg, acceptableHueRange)
        (foundObject, x, y, width, height,
         aspectRatio) = detectTrackedObject(hsvImg, bgrImg, lowerColourRange,
                                            upperColourRange)

        if foundObject:
            if uploadSnapshots:
                labelledImageName = '%s/%u-labelled.jpg' % (config.imagePath,
                                                            timestamp)
                cv2.imwrite(labelledImageName, bgrImg)
                uploadSnapshot(labelledImageName)

            msg = 'Calibrated with object of aspect ratio %.2f and average hue %.2f (scene width: %dpx)' % (
                aspectRatio, averageHue, cameraDimX)
            print(msg)
            udp.logToBotlab(msg, False)
        else:
            time.sleep(1)
Esempio n. 6
0
def botLabCallback(data):
    dataString = data.decode('ascii')
    payload = dataString.split()

    if len(payload) < 7:   # name + command + maxVelocity + pivotTurnSpeed + 2x bot option bytes + 1x Pi option byte
        print('Received invalid command payload: [%s]' % dataString)
        return

    if payload[0] == config.name:
        print('Ignoring broadcast command from myself')
        return

    command = int(payload[1])
    globals.currentCommandPhase = 0
    success = False
    errMsg  = ''

    if command == enums.PI_CMD_TRANSIT_WAYPOINTS:
        (success, errMsg) = commands.executeTransit(payload[2:])
    elif command == enums.PI_CMD_SET_BOT_OPTION:
        (success, errMsg) = commands.executeSetBotOption(payload[2:])
    elif command == enums.PI_CMD_ROTATE_AND_DRIVE:
        (success, errMsg) = commands.executeRotateAndDrive(payload[2:])
    elif command == enums.PI_CMD_FIND_OBJECT:
        (success, errMsg) = commands.executeFindObject(payload[2:])
    elif command == enums.PI_CMD_CALIBRATE_CAMERA:
        (success, errMsg) = commands.executeCalibrateCamera(payload[2:])
    elif command == enums.PI_CMD_REPORT_STATUS:
        (success, errMsg) = commands.executeReportStatus(payload[2:])
    else:
        errMsg = 'Unknown command'

    if not success:
        print('Failed to execute command [%2X]: %s (payload: %s)' % (command, errMsg, dataString))
        msg = 'Failed to execute cmd [%2X]: %s' % (command, errMsg)
        udp.logToBotlab(msg, False)

    return 0
Esempio n. 7
0
def i2cInterrupt(id, tick):
    """Handle an I2C interrupt to either send or receive data from the bot.
    """

    global localPi
    global slaveAddr
    global transmitSegments
    global segmentsSent

    s, b, d = localPi.bsc_i2c(slaveAddr)

    if b:
        if d[0] == ord(
                'p') and len(transmitSegments) != 0 and segmentsSent < len(
                    transmitSegments):
            """CMD: PING: Send the next waypoint I2C segment."""
            s, b, d = localPi.bsc_i2c(slaveAddr,
                                      transmitSegments[segmentsSent])
            segmentsSent += 1

        elif d[0] == ord('s') and b == 3:
            """CMD: REPORT STATUS: """
            mv = struct.unpack_from('>H', d, 1)[0]

            msg = 'Battery Level: %d mV' % mv
            print(msg)
            udp.sendPong('255.255.255.255', config.udpBotLabPort, mv)

        elif d[0] == ord('r'):
            """CMD: REPORT SNAPSHOT: Receive the next pose snapshot report."""
            if b == 14:
                x = struct.unpack_from('>h', d, 2)[0]
                y = struct.unpack_from('>h', d, 4)[0]
                headingPacked = struct.unpack_from('B', d, 6)[0]
                headingFloat = struct.unpack_from('B', d, 7)[0]
                distanceToObstacle = struct.unpack_from('>H', d, 8)[0]
                timestamp = struct.unpack_from('>H', d, 10)[0]
                detailByte = struct.unpack_from('>B', d, 12)[0]

                if headingPacked & 0x80:
                    heading = 0
                    heading -= (headingFloat / 100.0)
                    heading -= (headingPacked & 0x7F)
                else:
                    heading = (headingPacked & 0x7F) + (headingFloat / 100.0)

                # If ranging was disabled the distance to obstacle reported will always be 0
                if distanceToObstacle:
                    obstacleX = x + (distanceToObstacle * math.cos(heading))
                    obstacleY = y + (distanceToObstacle * math.sin(heading))
                else:
                    obstacleX = 0  # ensure that botlab doesn't draw any obstacles, we weren't measuring them
                    obstacleY = 0  # ensure that botlab doesn't draw any obstacles, we weren't measuring them

                print('%lu\t%d\t%d\t%f\t%d\t%d\t%d\t%u' %
                      (timestamp, x, y, heading, distanceToObstacle, obstacleX,
                       obstacleY, detailByte))

                msg = ('%lu\t%d\t%d\t%.2f\t%d\t%d\t%u' %
                       (timestamp, x, y, heading, obstacleX, obstacleY,
                        detailByte))
                udp.logToBotlab(msg, True)

                globals.currentX = x
                globals.currentY = y
                globals.currentHeading = heading

                if globals.currentCommand == enums.PI_CMD_TRANSIT_WAYPOINTS:
                    # If this is the last snapshot of a waypoint and it wasn't interrupted by an obstacle, it's a good one to follow
                    if (detailByte &
                            POSE_SNAPSHOT_DETAILBYTE_LAST_SNAPSHOT_FOR_WAYPOINT
                        ) and not (detailByte &
                                   POSE_SNAPSHOT_DETAILBYTE_ABORTED_WAYPOINT):
                        print('  above snapshot is follow me candidate')
                        waypoint = (x, y)
                        globals.followMeWaypoints.append(waypoint)

                    # If the last snapshot of the last waypoint and follow me mode is on, send all good waypoints
                    if (detailByte &
                            POSE_SNAPSHOT_DETAILBYTE_LAST_SNAPSHOT_FOR_JOURNEY
                        ) and globals.followMe:
                        # TODO: propagate optionByte1
                        udp.sendFollowMeCommand(globals.followMeWaypoints,
                                                globals.followMeMaxVelocity,
                                                globals.followMePivotTurnSpeed,
                                                0)
                elif globals.currentCommand == enums.PI_CMD_ROTATE_AND_DRIVE:
                    if detailByte & POSE_SNAPSHOT_DETAILBYTE_LAST_SNAPSHOT_FOR_WAYPOINT:
                        commands.executeRotateAndDrive(
                            globals.currentCommandPayload)
                elif globals.currentCommand == enums.PI_CMD_FIND_OBJECT:
                    if detailByte & POSE_SNAPSHOT_DETAILBYTE_LAST_SNAPSHOT_FOR_WAYPOINT:
                        commands.executeFindObject(
                            globals.currentCommandPayload)
Esempio n. 8
0
def executeFindObject(commandPayload):
    maxVelocity = int(commandPayload[0])
    pivotTurnSpeed = int(commandPayload[1])
    optionByte1 = int(commandPayload[2])
    optionByte2 = int(commandPayload[3])
    piOptionByte1 = int(commandPayload[4])
    rotationAngle = int(commandPayload[5])
    rotationIterations = int(commandPayload[6])
    objectName = commandPayload[7]
    distance = int(commandPayload[8])

    if not config.supportsCamera:
        return ('False', 'Camera not supported')

    if globals.currentCommandPhase >= rotationIterations:
        globals.currentCommand = 0
        globals.currentCommandPhase = 0
        return (False, 'Object not found')

    msg = ('Looking for [%s] (attempt %d of %d)') % (
        objectName, globals.currentCommandPhase + 1, rotationIterations)
    print(msg)
    udp.logToBotlab(msg, False)

    foundObject = False
    (targetX, targetY) = (0, 0)
    labels = ''

    # Look for the object, there may be no need to rotate
    if objectName == 'redbox':
        (foundObject, targetX, targetY) = imgrecognition.detectRedBox(
            globals.currentX, globals.currentY, globals.currentHeading,
            piOptionByte1 & enums.PI_OPTION_UPLOAD_SNAPSHOTS)
    else:
        (foundObject, labels) = imgrecognition.detectNamedObjectInSnapshot(
            objectName, piOptionByte1 & enums.PI_OPTION_UPLOAD_SNAPSHOTS)

        if foundObject and distance:
            # We've been commanded to travel this far toward the object we've found
            targetX = globals.currentX + (distance *
                                          math.cos(globals.currentHeading))
            targetY = globals.currentY + (distance *
                                          math.sin(globals.currentHeading))

    if foundObject:
        globals.currentCommand = 0
        globals.currentCommandPhase = 0

        if objectName == 'redbox':
            msg = 'Found [redbox] at (%d, %d)' % (targetX, targetY)
        else:
            msg = 'Found [%s]' % objectName

        if distance:
            waypoints = []
            waypoint = (int(targetX), int(targetY))
            waypoints.append(waypoint)

            if piOptionByte1 & enums.PI_OPTION_FOLLOW_ME_MODE:
                # Send another bot there, not me
                msg = (
                    'Found [%s], directing others to (%d,%d) [maxVelocity: %d, pivotSpeed: %d, optionByte1: %d]'
                    % (objectName, targetX, targetY, maxVelocity,
                       pivotTurnSpeed, optionByte1))
                udp.sendFollowMeCommand(waypoints, maxVelocity, pivotTurnSpeed,
                                        optionByte1)
            else:
                msg = (
                    'Found [%s], driving %d cm from (%d,%d) to (%d,%d) [maxVelocity: %d]'
                    % (objectName, distance, globals.currentX,
                       globals.currentY, targetX, targetY, maxVelocity))
                transmitSegments = i2c.buildTransmitSegments(
                    waypoints, maxVelocity, pivotTurnSpeed, optionByte1,
                    optionByte2)
                i2c.registerTransmitSegments(transmitSegments)

        print(msg)
        udp.logToBotlab(msg, False)

        return (True, '')
    else:
        msg = 'Saw: %s' % labels
        udp.logToBotlab(msg, False)

    globals.currentCommand = enums.PI_CMD_FIND_OBJECT
    globals.currentCommandPayload = commandPayload
    globals.currentCommandPhase += 1

    waypoints = []
    waypoint = (rotationAngle, 0)
    waypoints.append(waypoint)

    transmitSegments = i2c.buildTransmitSegments(waypoints, maxVelocity,
                                                 pivotTurnSpeed, optionByte1,
                                                 enums.BOT_OPTION2_ROTATE)
    i2c.registerTransmitSegments(transmitSegments)

    return (True, '')