Controller Info Menu

I am trying to program a controller menu that shows values of different sensors by moving the controller joystick up, down, left, or right. I am coding this in python. The program compiles and downloads fine but freezes and crashes when moving the joystick at all. Some help would be appreciated.
Code:

        if con.axis2.position(PercentUnits.PCT) > 10 and abs(on.axis2.position(PercentUnits.PCT)) > abs(con.axis1.position(PercentUnits.PCT)): #UP
            con.screen.set_cursor(1,0)
            con.screen.print_('Tray: {}                  ' .format(TrayPot.value(RotationUnits.DEG)))
            con.screen.set_cursor(2,0)
            con.screen.print_('Arm: {}                   ' .format(ArmPot.value(RotationUnits.DEG)))
            con.screen.set_cursor(3,0)
            con.screen.print_('Gyro: {}                  ' .format(Inertial.rotation(RotationUnits.DEG)))
        elif con.axis2.position(PercentUnits.PCT) < -10 and abs(con.axis2.position(PercentUnits.PCT)) > abs(con.axis1.position(PercentUnits.PCT)): #DOWN
            con.screen.set_cursor(1,0)
            con.screen.print_('Auton: {}        ' .format(Auton))
            con.screen.set_cursor(2,0)
            con.screen.print_('                          ')
            con.screen.set_cursor(3,0)
            con.screen.print_('Arm Temp: {}C             ' .format(ArmMotor.temperature(TemperatureUnits.CELSIUS)))
        elif con.axis1.position(PercentUnits.PCT) > 10 and abs(con.axis1.position(PercentUnits.PCT)) > abs(con.axis2.position(PercentUnits.PCT)): #RIGHT
            con.screen.set_cursor(1,0)
            con.screen.print_('                          ')
            con.screen.set_cursor(2,0)
            con.screen.print_('        Empty Menu        ')
            con.screen.set_cursor(3,0)
            con.screen.print_('                          ')
        elif con.axis1.position(PercentUnits.PCT) < -10 and abs(con.axis1.position(PercentUnits.PCT)) > abs(con.axis2.position(PercentUnits.PCT)): #LEFT
            con.screen.set_cursor(1,0)
            con.screen.print_('                          ')
            con.screen.set_cursor(2,0)
            con.screen.print_('        Empty Menu        ')
            con.screen.set_cursor(3,0)
            con.screen.print_('                          ')
        else:
            con.screen.set_cursor(1,0)
            con.screen.print_('     Welcome To       ')
            con.screen.set_cursor(2,0)
            con.screen.print_("   1429B's Program    ")
            con.screen.set_cursor(3,0)
            con.screen.print_('        Enjoy         ')

Sorry I missed this one.

First up, the string format method is from Python 3. RMS Python is currently built on a pared down version of Python 2.5. Our documentation on the controller’s print method has some information about how to format strings in this version of Python.

Next up, it’s not a problem that would crash your program, but any messages sent to the controller within 50ms of the last message will be ignored on the VEXos layer. If you need help working around that limitation, I can offer suggestions.

1 Like

Suggestions would be great! Criticism is the best form of education

A 50ms delay after each of three lines is pretty long, so a way to separate printing from normal program flow is usually desirable. There are various ways to accomplish this, from just keeping track of the time the last message was sent in the main loop to starting another thread to just do controller screen updates.

1 Like

Could you show me what that would look like? I never really got threads to work. Haven’t dabbled to much into multi threading

It’s fairly straightforward in RMS Python:

def some_function():
  # Whatever you want the thread to do goes here, often something in a loop
  while True:
    pass

# To start the thread (only do this once if it is looped):
sys.run_in_thread(some_function)

The interpreter will automatically switch back and forth between running threads. Do be aware that any thread you create will not be automatically ended when the competition state switches between auton, driver, or disable.

Here’s a write-up of threading in RMS Python that I did a while back. It has some links to examples of threading at the bottom of the page.

1 Like

So inside my thread would be a loop consisting of printing the commands on the screen. That thread would go inside my driver while loop. And set the controller position to change a variable that determines the print inside the thread?

Nope. If you start a thread in a loop, it will get started again every time the loop loops. Threads are pretty expensive in terms of computer resources, and your program would quickly stop working correctly. Take a look at the featured example for an idea of where you’d want to start them. You want to make sure that they are only created once if their run time is unlimited, or created infrequently if they have a finite run time.

2 Likes

Right. So in my drivercontrol thread but outside of the while loop.

Your driver control thread can start multiple times. If you start your program before plugging into competition control, for example, your driver control thread starts at least twice.

1 Like

Is this what you’re suggesting?

def ControllerMenu():
    global ControllerMenuVar
    while vex.Competition.is_driver_control():
        if ControllerMenuVar == 'Up':
            con.screen.set_cursor(1,0)
            con.screen.print_('Tray:', TrayPot.value(RotationUnits.DEG))
            con.screen.set_cursor(2,0)
            con.screen.print_('Arm:', ArmPot.value(RotationUnits.DEG))
            con.screen.set_cursor(3,0)
            con.screen.print_('Auton:', Auton)
        elif ControllerMenuVar == 'Down':
            con.screen.set_cursor(1,0)
            con.screen.print_('                          ')
            con.screen.set_cursor(2,0)
            con.screen.print_('Tray Temp:' , TrayMotor.temperature(TemperatureUnits.CELSIUS))
            con.screen.set_cursor(3,0)
            con.screen.print_('Arm Temp:', ArmMotor.temperature(TemperatureUnits.CELSIUS))
        elif ControllerMenuVar == 'Right':
            con.screen.set_cursor(1,0)
            con.screen.print_('                          ')
            con.screen.set_cursor(2,0)
            con.screen.print_('        Empty Menu        ')
            con.screen.set_cursor(3,0)
            con.screen.print_('                          ')
        elif ControllerMenuVar == 'Left':
            con.screen.set_cursor(1,0)
            con.screen.print_('                          ')
            con.screen.set_cursor(2,0)
            con.screen.print_('        Empty Menu        ')
            con.screen.set_cursor(3,0)
            con.screen.print_('                          ')
        else:
            con.screen.set_cursor(1,0)
            con.screen.print_('     Welcome To       ')
            con.screen.set_cursor(2,0)
            con.screen.print_("   1429B's Program    ")
            con.screen.set_cursor(3,0)
            con.screen.print_('        Enjoy         ')
def drivercontrol():
    sys.run_in_thread(ControllerMenu)
    while True:
        global ControllerMenuVar
        ########################################################################
        ############################CONTROLLER MENU#############################
        if con.axis2.position(PercentUnits.PCT) > 10 and abs(on.axis2.position(PercentUnits.PCT)) > abs(con.axis1.position(PercentUnits.PCT)): #UP
            ControllerMenuVar = 'Up'
        elif con.axis2.position(PercentUnits.PCT) < -10 and abs(con.axis2.position(PercentUnits.PCT)) > abs(con.axis1.position(PercentUnits.PCT)): #DOWN
            ControllerMenuVar = 'Down'
        elif con.axis1.position(PercentUnits.PCT) > 10 and abs(con.axis1.position(PercentUnits.PCT)) > abs(con.axis2.position(PercentUnits.PCT)): #RIGHT
            ControllerMenuVar = 'Right'
        elif con.axis1.position(PercentUnits.PCT) < -10 and abs(con.axis1.position(PercentUnits.PCT)) > abs(con.axis2.position(PercentUnits.PCT)): #LEFT
            ControllerMenuVar = 'Left'
        else:
            ControllerMenuVar = 'Else'

That takes care of running the thread more than once. Just don’t forget the 50ms wait between sending controller messages and you should be in business.

2 Likes

I’m not exactly sure where I would place the sleep timers. Some guidance would be great!

Also probably the same issue but could you help me with this simple Brain Menu I am working on?
Im getting the same issue. It compiles but it crashes as soon as I touch the brain. This is placed in my driver control loop. I also have Vsync off for the brain.
This is the code:

       if Auton == 'BluePage' or Auton == 'BlueLeft' or Auton == 'BlueRight':
            if brain.screen.pressing():
                brain.screen.render()
                sys.sleep(.1)
                if 153 > brain.screen.x_position() > 13 and 212 > brain.screen.y_position() > 119:
                    Auton = 'BlueLeft'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("BlueLeft.png",0,0)
                    brain.screen.render()
                elif 310 > brain.screen.x_position() > 170 and 212 > brain.screen.y_position() > 119:
                    Auton = 'BlueRight'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("BlueLeft.png",0,0)
                    brain.screen.render()
                elif 90 > brain.screen.x_position() > 30 and 110 > brain.screen.y_position() > 10:
                    Auton = 'MenuPage'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("MenuPage.png",0,0)
                    brain.screen.render()
        elif Auton == 'RedPage' or Auton == 'RedLeft' or Auton == 'RedRight':
            if brain.screen.pressing():
                brain.screen.render()
                sys.sleep(.1)
                if 153 > brain.screen.x_position() > 13 and 212 > brain.screen.y_position() > 119:
                    Auton = 'RedLeft'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("RedLeft.png",0,0)
                    brain.screen.render()
                elif 310 > brain.screen.x_position() > 170 and 212 > brain.screen.y_position() > 119:
                    Auton = 'RedRight'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("RedRight.png",0,0)
                    brain.screen.render()
                elif 90 > brain.screen.x_position() > 30 and 110 > brain.screen.y_position() > 10:
                    Auton = 'MenuPage'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("MenuPage.png",0,0)
                    brain.screen.render()
        elif Auton == 'MenuPage' or Auton == 'Skills' or Auton == 'Test':
            if brain.screen.pressing():
                brain.screen.render()
                sys.sleep(.1)
                if 310 > brain.screen.x_position() > 170 and 111 > brain.screen.y_position() > 46:
                    Auton = 'RedPage'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("RedPage.png",0,0)
                    brain.screen.render()
                elif 153 > brain.screen.x_position() > 13 and 111 > brain.screen.y_position() > 46:
                    Auton = 'BluePage'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("BluePage.png",0,0)
                    brain.screen.render()
                elif 153 > brain.screen.x_position() > 13 and 193 > brain.screen.y_position() > 128:
                    Auton = 'Skills'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("Skills.png",0,0)
                    brain.screen.render()
                elif 310 > brain.screen.x_position() > 170 and 193 > brain.screen.y_position() > 128:
                    Auton = 'Test'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("Test.png",0,0)
                    brain.screen.render()

This is what I came up with for the controller menu timers. Let me know if its wrong:

def ControllerMenu():
    global ControllerMenuVar
    while vex.Competition.is_driver_control():
        if ControllerMenuVar == 'Up':
            con.screen.set_cursor(1,0)
            con.screen.print_('Tray:', TrayPot.value(RotationUnits.DEG))
            sys.sleep(.05)
            con.screen.set_cursor(2,0)
            con.screen.print_('Arm:', ArmPot.value(RotationUnits.DEG))
            sys.sleep(.05)
            con.screen.set_cursor(3,0)
            con.screen.print_('Auton:', Auton)
            sys.sleep(.05)
        elif ControllerMenuVar == 'Down':
            con.screen.set_cursor(1,0)
            con.screen.print_('                          ')
            sys.sleep(.05)
            con.screen.set_cursor(2,0)
            con.screen.print_('Tray Temp:' , TrayMotor.temperature(TemperatureUnits.CELSIUS))
            sys.sleep(.05)
            con.screen.set_cursor(3,0)
            con.screen.print_('Arm Temp:', ArmMotor.temperature(TemperatureUnits.CELSIUS))
            sys.sleep(.05)
        elif ControllerMenuVar == 'Right':
            con.screen.set_cursor(1,0)
            con.screen.print_('                          ')
            sys.sleep(.05)
            con.screen.set_cursor(2,0)
            con.screen.print_('        Empty Menu        ')
            sys.sleep(.05)
            con.screen.set_cursor(3,0)
            con.screen.print_('                          ')
            sys.sleep(.05)
        elif ControllerMenuVar == 'Left':
            con.screen.set_cursor(1,0)
            con.screen.print_('                          ')
            sys.sleep(.05)
            con.screen.set_cursor(2,0)
            con.screen.print_('        Empty Menu        ')
            sys.sleep(.05)
            con.screen.set_cursor(3,0)
            con.screen.print_('                          ')
            sys.sleep(.05)
        else:
            con.screen.set_cursor(1,0)
            con.screen.print_('     Welcome To       ')
            sys.sleep(.05)
            con.screen.set_cursor(2,0)
            con.screen.print_("   1429B's Program    ")
            sys.sleep(.05)
            con.screen.set_cursor(3,0)
            con.screen.print_('        Enjoy         ')
            sys.sleep(.05)
            

I don’t see any obvious errors here. If you comment out the brain menu stuff, does it work? If you comment out just the image drawing, does it work? The usual procedure if something breaks after you add a bunch of stuff at once is to take it back and keep adding smaller pieces until it breaks again, then see if just that piece is broken or if it has to be with the others to break, etc. Then once you have a good handle on what exactly is causing the problem, it’s much easier to investigate it yourself or ask for help with it.

1 Like

So my Controller Menu started working after all you recommended, but only works when moving my joystick left or right due to it being an “Empty Menu” and not outputting any actual values, but crashes as soon as I move up and down which is supposed to show values. Any ideas?

As for the Brain Menu I am gonna try putting it in a seperate thread which I just created, will test soon but if there is any obvious errors let me know.

def BrainMenu():
    while vex.Competition.is_driver_control():
        while Auton == 'BluePage' or Auton == 'BlueLeft' or Auton == 'BlueRight':
            if brain.screen.pressing():
                brain.screen.render()
                sys.sleep(.1)
                if 153 > brain.screen.x_position() > 13 and 212 > brain.screen.y_position() > 119:
                    Auton = 'BlueLeft'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("BlueLeft.png",0,0)
                    brain.screen.render()
                elif 310 > brain.screen.x_position() > 170 and 212 > brain.screen.y_position() > 119:
                    Auton = 'BlueRight'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("BlueLeft.png",0,0)
                    brain.screen.render()
                elif 90 > brain.screen.x_position() > 30 and 110 > brain.screen.y_position() > 10:
                    Auton = 'MenuPage'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("MenuPage.png",0,0)
                    brain.screen.render()
        while Auton == 'RedPage' or Auton == 'RedLeft' or Auton == 'RedRight':
            if brain.screen.pressing():
                brain.screen.render()
                sys.sleep(.1)
                if 153 > brain.screen.x_position() > 13 and 212 > brain.screen.y_position() > 119:
                    Auton = 'RedLeft'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("RedLeft.png",0,0)
                    brain.screen.render()
                elif 310 > brain.screen.x_position() > 170 and 212 > brain.screen.y_position() > 119:
                    Auton = 'RedRight'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("RedRight.png",0,0)
                    brain.screen.render()
                elif 90 > brain.screen.x_position() > 30 and 110 > brain.screen.y_position() > 10:
                    Auton = 'MenuPage'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("MenuPage.png",0,0)
                    brain.screen.render()
        while Auton == 'MenuPage' or Auton == 'Skills' or Auton == 'Test':
            if brain.screen.pressing():
                brain.screen.render()
                sys.sleep(.1)
                if 310 > brain.screen.x_position() > 170 and 111 > brain.screen.y_position() > 46:
                    Auton = 'RedPage'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("RedPage.png",0,0)
                    brain.screen.render()
                elif 153 > brain.screen.x_position() > 13 and 111 > brain.screen.y_position() > 46:
                    Auton = 'BluePage'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("BluePage.png",0,0)
                    brain.screen.render()
                elif 153 > brain.screen.x_position() > 13 and 193 > brain.screen.y_position() > 128:
                    Auton = 'Skills'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("Skills.png",0,0)
                    brain.screen.render()
                elif 310 > brain.screen.x_position() > 170 and 193 > brain.screen.y_position() > 128:
                    Auton = 'Test'
                    brain.screen.clear_screen()
                    brain.screen.draw_image_from_file("Test.png",0,0)
                    brain.screen.render()

I am running this thread in the driver control outside of the while loop.

Ah, I missed what should have been an obvious one to spot. print_ only takes one argument and you are giving it multiple arguments. Take a look at the documentation I linked up above again.