Improve the Control App

That was pretty neat. With just a few lines of MVP code your robot should have picked up on some Fedoras in the vincinity. But we are of course striving for more.

We will enhance the brains …​ I mean the code of your robot:

We have some improved and more complex code for you do work on. This first part is for finding the hat.

  • It puts the more complex function to find the hat and drive towards it in the function search_for_hat()

  • It uses parameters to easily test, optimize and tune different values in your code

  • It renders the bounding boxes to an Image file, so that you see what the robot sees

Add the new "search_for_hat()" function

Right before the function def take_picture(image_file_name): add this code (as usual check you identation)

def search_for_hat():
    # Define switch for identifying found and intercepted hats across functions
    global hat_found_and_intercepted

    print('\n### Search For Hat Mode - START ###')

    # Circle, capture images, apply model and drive towards an identified object
    turn_counter = 0
    while thread_event.is_set():
        print('\n')

        # Take picture and find the object with the highest probabilty of being a hat
        objects = take_picture_and_detect_objects()
        coordinates = find_highest_score(objects)

        # Output distance from sensor
        print ('Got distance -> ', distance())

        # Check if there is an obstacle ahead
        if distance_int() <= min_distance_to_obstacle:
            print('### Search For Hat Mode - END: Obstacle detected! ###')
            return

        # Align to and drive towards identified object
        if coordinates and coordinates.confidence_score > confidence_threshold:
            print(f'''Object with highest score -> [
                confidence score: {coordinates.confidence_score},
                x upper left corner: {coordinates.x_upper_left},
                y upper left corner: {coordinates.y_upper_left},
                x lower right corner: {coordinates.x_lower_right},
                y lower right corner: {coordinates.y_lower_right},
                object class: {coordinates.object_class} ]''')

            # Align so that the most likely hat identified is in the center (within 20 pixels)
            center_x = (coordinates.x_upper_left + coordinates.x_lower_right) / 2
            print(f'center_x: {center_x}')

            # Center of hat needs to be within 20 pixels
            if abs(image_resolution_x/2-center_x) >= 20:
                if center_x < 320:
                    turn_left(10)
                else:
                    turn_right(10)

            # Determine size of the object in the image (not the real size!)
            delta = coordinates.x_lower_right - coordinates.x_upper_left
            print(f'delta: {delta}')

            # Move forward, if size of identified object in image is not big enough
            # (i.e. if it's not close enough)
            if delta < delta_threshold:
                move_forward(10)
            else:
                hat_found_and_intercepted = True
                print('### Search For Hat Mode - END: OJECT FOUND ! ###')
                return

        else:
            # Circle in case no hat could be identied
            if turn_counter <= 360:
                turn_right(10)
                turn_counter = turn_counter + 10
            else:
                # After a full circle, move forward and circle again to find the hat
                move_forward(40)
                turn_counter = 0

    print('### Search For Hat Mode - END ###')

Look for the line @application.route('/') and right above add these parameters

image_resolution_x = 640 # pixels; resolution of camera used in robot
confidence_threshold = 0.6 # e.g. 0.6 = 60%; confidence at which an object identified as hat is intercepted
delta_threshold = 280 # pixels; delta for standard fedora (defines minimum desired pixel size of fedora in image)
hat_found_and_intercepted = False # boolean; switch for a found and intercepted hat
# Define parameters for hat search and obstacle bypass algos
min_distance_to_obstacle = 300 # mm; distance at which the obstacle bypass mode is activated
angle_delta = 90 # deg; angle used for sidestepping obstacle

Now you can call these functions from inside the startRobot() function like so

    # Drop your code here
    # Initialize switch for identifying found and intercepted hats across functions
    global hat_found_and_intercepted
    hat_found_and_intercepted = False

    # Main loop running until one hat is properly identified and intercepted (or the app ist stopped)
    while thread_event.is_set() and not hat_found_and_intercepted:

        # Search for the hat and intercrept it
        search_for_hat()

    print('Done')

Exercise

Your mission: Your robot must autonomously find the red fedora and drive towards it. The mission will count as accomplished when the robot is in front of the fedora.

The playing field where the fedora and robot will be placed is defined inside these boundaries:

challenge1

Once you little mechanical friend has completed his mission, you may continue to the next chapter.