Image

Seaquence

(Formerly "Six Seas of Technological Development")

Description of Current Technological Solution

Hardware wise, our project has four separate colored stations, or EV3 bricks. Each station has a button and a flag fixed to a motor of the proper color. Each station will be capable of rotating the flag, to indicate that it is a part of the sequence, and sensing touch as the children respond.

These four stations are all in turn controlled by a Raspberry Pi that acts as the “Simon”. This central computer runs the code that instructs the four stations to display a sequence of colors for the children to repeat. Then, it waits and receives information from the four stations to piece together a collective response. Finally, it analyzes the response to determine success or failure.

Software wise, the code is all one file, run by the Raspberry Pi. First, it initializes all variables and devices for the game and then defines two subfunctions. The first is for recording responses when only one color input is expect. The second is a function for recording two colors at once when the game requires the children to press two buttons simultaneously. From there, each level is a loop that iterates over the three sequences for each level. Within each level loop, an embedded while loop contains the rest of the logic. Within this embedded while loop, a series of lines instructs the four stations to produce the sequence to be repeated based on the index of the parent level loop. After producing the sequence, the code awaits sensory input using one of the subprograms defined above. Concluding the loop are two if statements that determine whether the response is correct or incorrect. When a correct solution triggers the if statement, the loop will be broken; when an incorrect solution is found, the loop resets by showing the sequence again. An incorrect solution is only identified when the length of the response is the same as that of the solution.

One additional feature included for prototype testing was a "kill switch" which aborts the current sequence in the case that the children become confused or are otherwise struggling. It is also used to pause between levels, allowing time for the audio instructions to play.

During testing, we broke the code into three separate files. Each file contained the initialization code, subfunctions, and one level. This allowed us to jump around throughout the game more easily.

For the sake of testing, the built-in-map and sounds were both faux-robotic (a PowerPoint presentation and keyboard sounds over a Bluetooth speaker), operated by one of our team members during testing.

Currently, there are no "captain" or "treasure chest" levels for the end of the game.

Pictures and Videos

Image

Current Code

#!/usr/bin/python3

def main():
    # define hardware
    gpg = Device("this")
    killSwitch = gpg.init_button_sensor("AD2")
    print('Pi Initiated')
    stationR = Device('172.16.216.92')
    motorR = stationR.LargeMotor('outA')
    buttonR = stationR.TouchSensor('in1')
    print('Red Initiated')
    stationY = Device('172.16.143.207')
    motorY = stationY.LargeMotor('outA')
    buttonY = stationY.TouchSensor('in1')
    print('Yellow Initiated')
    stationG = Device('130.64.142.61')
    motorG = stationG.LargeMotor('outA')
    buttonG = stationG.TouchSensor('in1')
    print('Green Initiated')
    #stationB = Device('')
    #motorB = stationB.LargeMotor('outA')
    #buttonB = stationB.TouchSensor('in1')
    #print('Blue Initiated')

    # "receive" function
    # 1 = red
    # 2 = yellow
    # 3 = green
    # 4 = blue
    def receive( response, i ):
        if buttonR.is_pressed == 1:
            motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            response.append(1)
            print(response)
            i=i+1
            sleep(1)
        elif buttonY.is_pressed == 1:
            motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            response.append(2)
            print(response)
            i=i+1
            sleep(1)
        elif buttonG.is_pressed == 1:
            motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            response.append(3)
            print(response)
            i=i+1
            sleep(1)
        #elif buttonB.is_pressed == 1:
            #motorB.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            #response.append(4)
            #print(response)
            #i=i+1
            #sleep(1)
        return

    # "receive2" function
    # 5 = red and yellow
    # 6 = red and green
    # 7 = red and blue
    # 8 = yellow and green
    # 9 = yellow and blue
    # 10 = green and blue
    def receive2( response, i):
        if buttonR.is_pressed == 1 and buttonY.is_pressed == 1:
            motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            response.append(5)
            print(response)
            i=i+1
            sleep(1)
        elif buttonR.is_pressed == 1 and buttonG.is_pressed == 1:
            motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            response.append(6)
            print(response)
            i=i+1
            sleep(1)
        #elif buttonR.is_pressed == 1 and buttonB.is_pressed == 1:
            #motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            #motorB.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            #response.append(7)
            #print(response)
            #i=i+1
            #sleep(1)
        elif buttonY.is_pressed == 1 and buttonG.is_pressed == 1:
            motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            response.append(8)
            print(response)
            i=i+1
            sleep(1)
        #elif buttonY.is_pressed == 1 and buttonB.is_pressed == 1:
            #motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            #motorB.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            #response.append(9)
            #print(response)
            #i=i+1
            #sleep(1)
        #elif buttonG.is_pressed == 1 and buttonB.is_pressed == 1:
            #motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            #motorB.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
            #response.append(10)
            #print(response)
            #i=i+1
            #sleep(1)
        return

    # wait for go
    while True:
        if killSwitch.is_button_pressed():
            print("Kill switch")
            break

    # LEVEL 1
    print('LEVEL 1')
    j = 1
    while j < 4:
        i = 1
        solutionA = [2]
        solutionB = [3]
        solutionC = [1]
        response=[]
        while True:
            if i == 1 and j == 1:
                print(solutionA)
                sleep(1)
                motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                i=0
            elif i == 1 and j == 2:
                print(solutionB)
                sleep(1)
                motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                i=0
            elif i == 1 and j == 3:
                print(solutionC)
                sleep(1)
                motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                i=0
            elif (response==solutionA and j==1) or (response==solutionB and j==2) or (response==solutionC and j==3):
                print(response)
                print('correct')
                break
            elif len(response)==1:
                print(response)
                print('wrong')
                response=[]
                i=1
                sleep(1)
            elif killSwitch.is_button_pressed():
                print("Kill switch")
                break
            else:
                receive( response , i )
        j = j + 1
    print('LEVEL 1 DONE')

    # wait for go
    while True:
        if killSwitch.is_button_pressed():
            print("Kill switch")
            break

    # LEVEL 2
    print('LEVEL 2')
    j = 1
    while j < 4:
        i = 1
        solutionA = [1,2,3]
        solutionB = [3,2,2]
        solutionC = [2,1,3]
        response=[]
        while True:
            if i == 1 and j == 1:
                print(solutionA)
                sleep(1)
                motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                i=0
            elif i == 1 and j == 2:
                print(solutionB)
                sleep(1)
                motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                i=0
            elif i == 1 and j == 3:
                print(solutionC)
                sleep(1)
                motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                i=0
            elif (response==solutionA and j==1) or (response==solutionB and j==2) or (response==solutionC and j==3):
                print(response)
                print('correct')
                break
            elif len(response)==3:
                print(response)
                print('wrong')
                response=[]
                i=1
                sleep(1)
            elif killSwitch.is_button_pressed():
                print("Kill switch")
                break
            else:
                receive( response , i )
        j = j + 1
    print('LEVEL 2 DONE')

    # wait for go
    while True:
        if killSwitch.is_button_pressed():
            print("Kill switch")
            break

    # LEVEL 3
    print('LEVEL 3')
    j = 1
    while j < 4:
        i = 1
        solutionA = [5,6,8]
        solutionB = [6,5,8]
        solutionC = [8,6,5]
        response=[]
        while True:
            if i == 1 and j == 1:
                print(solutionA)
                sleep(1)
                motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                i=0
            if i == 1 and j == 2:
                print(solutionB)
                sleep(1)
                motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                i=0
            if i == 1 and j == 3:
                print(solutionC)
                sleep(1)
                motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                motorG.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                motorY.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                motorR.run_to_rel_pos(position_sp=360, speed_sp=400, stop_action="hold")
                sleep(1)
                i=0
            elif (response==solutionA and j==1) or (response==solutionB and j==2) or (response==solutionC and j==3):
                print(response)
                print('correct')
                break
            elif len(response)==3:
                print(response)
                print('wrong')
                response=[]
                i=1
                sleep(1)
            elif killSwitch.is_button_pressed():
                print("Kill switch")
                break
            else:
                receive2( response , i )
        j = j + 1
    print('LEVEL 3 DONE')

if __name__ == '__main__':
    main()

Updates for Final Version.

1: During the test we found out it was inconvenient to show kids the sequence again because we had to do a wrong sequence until the program began another loop. Therefore, we plan to add a button to start the challenge over, so that kids can watch the sequence again at any time they feel confused.

2: Since all the levels are quite different from each other, kids often feel confused about a new level even after they finished the previous one successfully. For that reason, we will make more detailed audio instructions for the kids and show them how to do the new sequence first. To achieve that, we need more pauses in the program to ensure all the guidance work smoothly.

3: In our current code, we programmed the motors to rotate a whole circle when showing sequences and when someone pressed buttons. However, this sometimes confused the children, for they didn’t know if the motion was a response of their action or showing them what they should do next. Therefore, we want to distinguish the movement of motors when showing the sequences from the movement as a response to their input.