Raspberry Pi RC Transmitter Phase 4 – Configuration Screens

Advertisements

Now that I have an OLED screen on the transmitter I need to be able to modify the transmitters settings. I have already added variables to set various options like channel reversing and centering. Now I need some screens to display the current values and modify them.

The 128 x 64 pixel screen can display 8 lines of text with the default font. If i display values for 8 channels then I wont be able to display a title. I am not ready to start modifying fonts before I can even change screens so I will split the channels into 2 columns to make room for a title line.

To make things cleaner when displaying multiple screens I added a function called draw_display that for arguments uses a string called title and a list of variables. The function the displays the title and 2 columns of variables with a label in front of each. Since the idea of the display is to modify these variables I need a cursor to select which variable I will modify so the function also takes an argument that is the current selected item and draws a rectangle around it.

#Function to draw the display
def draw_display(title, variables, selected_item):
    x = 0									#x and y starting points in top left of screen
    y = 0
    line_height = 12						#There a 5 lines drawn on the screen. 64 / 5 = 12
    column_width = 64						#2 columns
    space = 2								#A space is needed at the start of the left column or the cursor box will be drawn over the text
 
    #Draw the title text. The cursor box will be drawn first if the screen title is selceted
    if selected_item == 0:
        draw.rectangle((x, y, x + column_width*2 - 1, y + line_height), outline = 255, fill = 0)
    draw.text((x + space, y), title, font=font, fill=255)
	
    y = line_height + 2                    #Move down to the start of the variables

	#Draw the left hand column. If the currently selected item is the variable to be drawn then first draw a rectangle around it.
    for i in range(4):
        if i+1 == selected_item:
            draw.rectangle((x, y, x + column_width - 1, y + line_height), outline=255, fill=0)
        draw.text((x + space, y), "Ch " + str(i + 1) + ":" + str(variables[i]), font=font, fill=255)
        y = y + line_height

    y = line_height + 2					#Reset the x and y positions to the start of the right hand column
    x = column_width

	#Draw the right hand column again drawing a box if he item is selected.
    for i in range(4):
        if i+5 == selected_item:
            draw.rectangle((x, y, x + column_width - 1, y + line_height), outline=255, fill = 0)
        draw.text((x, y), "Ch " + str(i + 5) + ":" + str(variables[i + 4]), font=font, fill=255)
        y = y + line_height

To keep track of which screen is currently displayed and which item on the screen is currently selected two variables are added. A third variable is used to modify the number of screens that are displayed if I want to change that later.

current_screen = 0             #Currently displayed screen
max_number_of_screens = 5      #Maximum number of screens to display
current_item = 0               #Current item selected on screen

To select which screen is displayed and pass the appropriate values I added this code to near the end of the main loop.

if current_screen == 0:
    draw_display("Channel Output", ppm_chanels_us, current_item  
elif current_screen == 1:
    draw_display("Center Points", center, current_item)
elif current_screen == 2:
    draw_display("Upper End Points", upper_end_point, current_item)
elif current_screen == 3:
    draw_display("Lower End Points", lower_end_point, current_item)
elif current_screen == 4:
    draw_display("Reversing", reverse_channel, current_item)
elif current_screen == 5:
    draw_display("Expo", expo, current_item)

To scroll through the screens and select items I am using the D-pad on the Xbox controller. The remaining code from the Pygame demo that I started with includes a Event processor that prints a message on the console whenever a button is pressed on the controller. I had kept this in for debugging and have now added to it to monitor for events with the D-pad. Whenever an event occurs with the D-pad a series of if statements check which direction was pressed. If Up or Down are pressed the currently selected item is changed with some range checks added so the cursor doesn’t go off the top or bottom of the screen. If Left or Right are pressed either the screen is changed if the title is selected or the currently selected variable is changed.

# EVENT PROCESSING STEP
    for event in pygame.event.get(): # User did something
        if event.type == pygame.QUIT: # If user clicked close
            done=True # Flag that we are done so we exit this loop
        
        # Possible joystick actions: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION
        if event.type == pygame.JOYBUTTONDOWN:
            print("Joystick button pressed.")
        if event.type == pygame.JOYBUTTONUP:
            print("Joystick button released.")

        if event.type == pygame.JOYHATMOTION:
            hat = joystick.get_hat(0)
            if hat[0] == -1:
                if current_item == 0:
                    print("Hat LEFT pressed")
                    current_screen = current_screen - 1
                    if current_screen < 0:
                        current_screen = max_number_of_screens
                    print(current_screen)

                elif current_screen == 1:
                    center[current_item - 1] = center[current_item - 1] - 0.01

                elif current_screen == 2:
                    upper_end_point[current_item - 1] = upper_end_point[current_item - 1] - 0.01

                elif current_screen == 3:
                    lower_end_point[current_item - 1] = lower_end_point[current_item - 1] - 0.01

                elif current_screen == 4:
                    reverse_channel[current_item - 1] = -1

            elif hat[0] == 1:
                if current_item == 0:
                    print("Hat RIGHT pressed")
                    current_screen = current_screen + 1
                    if current_screen > max_number_of_screens:
                        current_screen = 0
                    print(current_screen)

                elif current_screen == 1:
                    center[current_item - 1] = center[current_item - 1] + 0.01

                elif current_screen == 2:
                    upper_end_point[current_item - 1] = upper_end_point[current_item - 1] + 0.01

                elif current_screen == 3:
                    lower_end_point[current_item - 1] = lower_end_point[current_item - 1] + 0.01

                elif current_screen == 4:
                    reverse_channel[current_item - 1] = 1

            elif hat[1] == -1:
                print("Hat DOWN pressed")
                current_item = current_item + 1
                if current_item > 8:
                    current_item = 8
                print(current_item)
            elif hat[1] == 1:
                print("Hat UP pressed")
                current_item = current_item - 1
                if current_item < 0:
                    current_item = 0
                print(current_item)

    for i in range(8):
        if center[i] > -0.01 and center[i] < 0.01:
            center[i] = 0

Since the value for center is a floating point number and can be 0 a check is added to ensure a 0 value is actually obtained when needed.

The next step will be to make any changes to the transmitters configuration be persistent when the transmitter is powered off. So I will need to look at writing the variables to an external file when changed.

Leave a Reply