diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 09bf5d6..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.pyc -__pycache__/ \ No newline at end of file diff --git a/robot/robot/__pycache__/robot.cpython-37.pyc b/robot/robot/__pycache__/robot.cpython-37.pyc new file mode 100644 index 0000000..0ebde78 Binary files /dev/null and b/robot/robot/__pycache__/robot.cpython-37.pyc differ diff --git a/robot/robot/robot.py b/robot/robot/robot.py new file mode 100644 index 0000000..93a737c --- /dev/null +++ b/robot/robot/robot.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +''' + This is a demo program showing how to use Mecanum control with the + RobotDrive class. +''' + +import wpilib +import commandbased + + +import subsystems.driveTrain + + + +class MyRobot(commandbased.CommandBasedRobot): + + def robotInit(self): + MyRobot.getRobot = lambda x=0:self + + self.dtSub = subsystems.driveTrain.DriveTrainSub(self) + self.driveController = wpilib.XboxController(0) + +# def teleopInit(self): +# print("Test Mode") +# dc = self.driveController +# while self.isOperatorControl(): +# leftSide = dc.getRawAxis(0) +# rightSide = dc.getRawAxis(1) +# +# self.dtSub.setTankDrive(leftSide, rightSide) +# +# print("Test Done") + + +#code to help run the robot + +#import sys +def exit(retval): + pass +# sys.exit(retval) + +if __name__ == '__main__': + try: + print(wpilib._impl.main.exit) + except: + wpilib._impl.main.exit = exit + wpilib.run(MyRobot,physics_enabled=True) \ No newline at end of file diff --git a/robot/team3200/robotMap.py b/robot/robot/robotMap.py similarity index 100% rename from robot/team3200/robotMap.py rename to robot/robot/robotMap.py diff --git a/robot/team3200/sim/config.json b/robot/robot/sim/config.json similarity index 100% rename from robot/team3200/sim/config.json rename to robot/robot/sim/config.json diff --git a/robot/robot/subsystems/__pycache__/driveTrain.cpython-37.pyc b/robot/robot/subsystems/__pycache__/driveTrain.cpython-37.pyc new file mode 100644 index 0000000..0e45624 Binary files /dev/null and b/robot/robot/subsystems/__pycache__/driveTrain.cpython-37.pyc differ diff --git a/robot/team3200/subsystems/driveTrain.py b/robot/robot/subsystems/driveTrain.py similarity index 67% rename from robot/team3200/subsystems/driveTrain.py rename to robot/robot/subsystems/driveTrain.py index 836ddd3..e066904 100644 --- a/robot/team3200/subsystems/driveTrain.py +++ b/robot/robot/subsystems/driveTrain.py @@ -3,29 +3,24 @@ from wpilib.command.subsystem import Subsystem import wpilib.drive.differentialdrive as dd - -from commands.joystickDrive import JoystickDrive - -import team3200 - import ctre - +import robot as robotPackage +from commands.joystickDrive import JoystickDrive class DriveTrainSub(Subsystem): ''' - This is the subsystem to controller the robots wheels. + This is the subsystem to control the robot's wheels. ''' - def __init__(self): + def __init__(self, robot): '''Initilizes the subsystem, gets the motors, - creates the drivetrain mixer - ''' + creates the drivetrain mixer''' + super().__init__("DriveTrainSub") - self.robot = team3200.getRobot(); + self.robot = robot + #self.robot = robotPackage.MyRobot.getRobot() self.driveMotors = {} self.driveMotors['leftMotor'] = ctre.WPI_TalonSRX(0) self.driveMotors['rightMotor'] = ctre.WPI_TalonSRX(1) - - self.driveTrain = dd.DifferentialDrive(**self.driveMotors) def setTankDrive(self, leftSide, rightSide): @@ -33,6 +28,7 @@ def setTankDrive(self, leftSide, rightSide): def setArcadeDrive(self, speed, rot): self.driveTrain.arcadeDrive(speed, rot) - + def initDefaultCommand(self): - self.setDefaultCommand(JoystickDrive(self.robot)) \ No newline at end of file + self.setDefaultCommand(JoystickDrive(self.robot)) + \ No newline at end of file diff --git a/robot/team3200/__init__.py b/robot/robot/subsystems/empty similarity index 100% rename from robot/team3200/__init__.py rename to robot/robot/subsystems/empty diff --git a/robot/team3200/commands/joystickDrive.py b/robot/team3200/commands/joystickDrive.py deleted file mode 100644 index 216e16a..0000000 --- a/robot/team3200/commands/joystickDrive.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- - -from wpilib.command import Command - -class JoystickDrive(Command): - """ - This command will read the joystick values that are used - to control the robot drive train and then set the drivetrain subsystem - """ - - def __init__(self, robot): - super().__init__("Joystick Drive") - self.robot = robot - self.requires(self.robot.dtSub) - - def execute(self): - dc = self.robot.driveController - leftSide = dc.getRawAxis(0) - rightSide = dc.getRawAxis(1) - - self.robot.dtSub.setTankDrive(leftSide,rightSide) - \ No newline at end of file diff --git a/robot/team3200/motorHelper.py b/robot/team3200/motorHelper.py deleted file mode 100644 index e69de29..0000000 diff --git a/robot/team3200/physics.py b/robot/team3200/physics.py deleted file mode 100644 index 6dad656..0000000 --- a/robot/team3200/physics.py +++ /dev/null @@ -1,56 +0,0 @@ -# -# See the notes for the other physics sample -# - - -from pyfrc.physics import drivetrains - - -class PhysicsEngine(object): - ''' - Simulates a 4-wheel mecanum robot using Tank Drive joystick control - ''' - - def __init__(self, physics_controller): - ''' - :param physics_controller: `pyfrc.physics.core.Physics` object - to communicate simulation effects to - ''' - - self.physics_controller = physics_controller - - - def update_sim(self, hal_data, now, tm_diff): - ''' - Called when the simulation parameters for the program need to be - updated. - - :param now: The current time as a float - :param tm_diff: The amount of time that has passed since the last - time that this function was called - ''' - - # Simulate the drivetrain - # -> Remember, in the constructor we inverted the left motors, so - # invert the motor values here too! - try: - - if hal_data['CAN'][1]['inverted']: - l_motor =-hal_data['CAN'][1]['value'] - else: - l_motor = hal_data['CAN'][1]['value'] - - if hal_data['CAN'][0]['inverted']: - r_motor = -hal_data['CAN'][0]['value'] - else: - r_motor = hal_data['CAN'][0]['value'] - - tm_diff = tm_diff * 0.5 - speed,rot = drivetrains.two_motor_drivetrain(l_motor,r_motor) - self.physics_controller.drive(speed,rot, tm_diff) - except: - l_motor = r_motor = 0 - self.physics_controller.drive(0,0, tm_diff) - - #print(hal_data['joysticks']) - #.mecanum_drivetrain(lr_motor, rr_motor, lf_motor, rf_motor,speed = 0.01) \ No newline at end of file diff --git a/robot/team3200/robot.py b/robot/team3200/robot.py deleted file mode 100644 index 7c6ea5e..0000000 --- a/robot/team3200/robot.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python3 -''' - This is a demo program showing how to use Mecanum control with the - RobotDrive class. -''' - -#add 'team3200' module to the search path -import os -import sys -sys.path.insert(0, os.getcwd() + "\\..") -import team3200 -import wpilib - -import commandbased - -import subsystems.driveTrain - -#main robot - -class MyRobot(commandbased.CommandBasedRobot): - - def robotInit(self): - team3200.getRobot = lambda x=0:self - self.dtSub = subsystems.driveTrain.DriveTrainSub() - self.driveController = wpilib.XboxController(0) - -# def teleopInit(self): -# print("Test Mode") -# dc = self.driveController -# while self.isOperatorControl(): -# leftSide = dc.getRawAxis(0) -# rightSide = dc.getRawAxis(1) -# -# self.dtSub.setTankDrive(leftSide,rightSide) -# -# print("Test Done") - - -#code to help run the robot - -#import sys -def exit(retval): - pass -# sys.exit(retval) - -if __name__ == '__main__': - try: - #patch no exit error if not running on robot - try: - print(wpilib._impl.main.exit) - except: - wpilib._impl.main.exit = exit - - #fixes simulation rerun errors. - #todo verify this causes no issues on robot - wpilib.DriverStation._reset() - - #patch simulation - #we update the simluation files to ours. If we update WPIlib these may break - import sim.ui - import sim.pygame_joysticks - import pyfrc.sim - import pyfrc.sim.pygame_joysticks - pyfrc.sim.SimUI = sim.ui.SimUI - pyfrc.sim.pygame_joysticks.UsbJoysticks = sim.pygame_joysticks.UsbJoysticks - except Exception as err: - print("Failed to patch runtime. Error", err) - - wpilib.run(MyRobot,physics_enabled=True) \ No newline at end of file diff --git a/robot/team3200/sim/pygame_joysticks.py b/robot/team3200/sim/pygame_joysticks.py deleted file mode 100644 index c341d2e..0000000 --- a/robot/team3200/sim/pygame_joysticks.py +++ /dev/null @@ -1,70 +0,0 @@ -import pygame -from hal_impl.data import hal_data - -class UsbJoysticks(object): - - def __init__(self, ui): - pygame.init() - - self.ui = ui - - self.joysticks = self.getUsbJoystickList() - self.initJoystickList(self.joysticks) - - def getUsbJoystickList(self): - joysticks = [] - - for i in range(pygame.joystick.get_count()): - joysticks.append(pygame.joystick.Joystick(i)) - return joysticks - - def initJoystickList(self, joystickList): - for i, joystick in enumerate(joystickList): - joystick.init() - if i < len(hal_data['joysticks']): - hal_data['joysticks'][i]['name'] = joystick.get_name() - - def update(self): - pygame.event.get() - - for i in range(len(self.joysticks)): - joystick = self.joysticks[i] - ui_joystick = self.ui.joysticks[i] - - ui_axes = ui_joystick[0] - - for axis in range(joystick.get_numaxes()): - if axis == 6: - break - - ui_current_axis = ui_axes[axis] - value = joystick.get_axis(axis) - - #xbox controller trigger fix - #map axis 2+ to axis 3 Left Trigger 0-1 - #map axis 2- to axis 5 Right Trigger 0-1 - if axis == 2: - axisValue = value - value = 0 if axisValue <= 0 else axisValue - ui_current_axis.set_value(value) - #map axis 5 to - ui_current_axis = ui_axes[5] - value = 0 if axisValue >= 0 else abs(axisValue) - - - ui_current_axis.set_value(value) - - ui_buttons = ui_joystick[1] - for button in range(joystick.get_numbuttons()): - if button == 10: - break - - ui_current_button = ui_buttons[button] - ui_current_button = ui_current_button[0] - - value = joystick.get_button(button) - - if value == False: - ui_current_button.deselect() - else: - ui_current_button.select() diff --git a/robot/team3200/sim/testJstick.py b/robot/team3200/sim/testJstick.py deleted file mode 100644 index 03c09ee..0000000 --- a/robot/team3200/sim/testJstick.py +++ /dev/null @@ -1,135 +0,0 @@ -import pygame - -# Define some colors -BLACK = ( 0, 0, 0) -WHITE = ( 255, 255, 255) - -# This is a simple class that will help us print to the screen -# It has nothing to do with the joysticks, just outputting the -# information. -class TextPrint: - def __init__(self): - self.reset() - self.font = pygame.font.Font(None, 20) - - def print(self, screen, textString): - textBitmap = self.font.render(textString, True, BLACK) - screen.blit(textBitmap, [self.x, self.y]) - self.y += self.line_height - - def reset(self): - self.x = 10 - self.y = 10 - self.line_height = 15 - - def indent(self): - self.x += 10 - - def unindent(self): - self.x -= 10 - - -pygame.init() - -# Set the width and height of the screen [width,height] -size = [500, 700] -screen = pygame.display.set_mode(size) - -pygame.display.set_caption("My Game") - -#Loop until the user clicks the close button. -done = False - -# Used to manage how fast the screen updates -clock = pygame.time.Clock() - -# Initialize the joysticks -pygame.joystick.init() - -# Get ready to print -textPrint = TextPrint() - -# -------- Main Program Loop ----------- -while done==False: - # 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.") - - - # DRAWING STEP - # First, clear the screen to white. Don't put other drawing commands - # above this, or they will be erased with this command. - screen.fill(WHITE) - textPrint.reset() - - # Get count of joysticks - joystick_count = pygame.joystick.get_count() - - textPrint.print(screen, "Number of joysticks: {}".format(joystick_count) ) - textPrint.indent() - - # For each joystick: - for i in range(joystick_count): - joystick = pygame.joystick.Joystick(i) - joystick.init() - - textPrint.print(screen, "Joystick {}".format(i) ) - textPrint.indent() - - # Get the name from the OS for the controller/joystick - name = joystick.get_name() - textPrint.print(screen, "Joystick name: {}".format(name) ) - - # Usually axis run in pairs, up/down for one, and left/right for - # the other. - axes = joystick.get_numaxes() - textPrint.print(screen, "Number of axes: {}".format(axes) ) - textPrint.indent() - - for i in range( axes ): - axis = joystick.get_axis( i ) - textPrint.print(screen, "Axis {} value: {:>6.3f}".format(i, axis) ) - textPrint.unindent() - - buttons = joystick.get_numbuttons() - textPrint.print(screen, "Number of buttons: {}".format(buttons) ) - textPrint.indent() - - for i in range( buttons ): - button = joystick.get_button( i ) - textPrint.print(screen, "Button {:>2} value: {}".format(i,button) ) - textPrint.unindent() - - # Hat switch. All or nothing for direction, not like joysticks. - # Value comes back in an array. - hats = joystick.get_numhats() - textPrint.print(screen, "Number of hats: {}".format(hats) ) - textPrint.indent() - - for i in range( hats ): - hat = joystick.get_hat( i ) - textPrint.print(screen, "Hat {} value: {}".format(i, str(hat)) ) - textPrint.unindent() - - textPrint.unindent() - - - # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT - - # Go ahead and update the screen with what we've drawn. - pygame.display.flip() - - # Limit to 20 frames per second - clock.tick(20) - -# Close the window and quit. -# If you forget this line, the program will 'hang' -# on exit if running from IDLE. -pygame.quit () diff --git a/robot/team3200/sim/ui.py b/robot/team3200/sim/ui.py deleted file mode 100644 index 95d8431..0000000 --- a/robot/team3200/sim/ui.py +++ /dev/null @@ -1,674 +0,0 @@ -''' - Note: http://bugs.python.org/issue11077 seems to indicate that tk is - supposed to be thread-safe, but everyone else on the net insists that - it isn't. Be safe, don't call into the GUI from another thread. -''' - -try: - import tkinter as tk -except ImportError: - print("pyfrc robot simulation requires python tkinter support to be installed") - raise - -import logging -import queue - -from hal_impl.data import hal_data - -from pyfrc import __version__ -from pyfrc.sim.field.field import RobotField -from pyfrc.sim.ui_widgets import CheckButtonWrapper, PanelIndicator, Tooltip, ValueWidget - -from pkg_resources import iter_entry_points - -logger = logging.getLogger(__name__) - -def _get_pos_callback(pos, root, selected): - def _fn(): - selected[0] = pos - root.destroy() - return _fn - - -def configure_starting_position(config_obj): - start_positions = config_obj['pyfrc']['robot']['start_positions'] - if not start_positions: - return - if len(start_positions) == 1: - selected = start_positions[0] - elif len(start_positions) > 1: - root = tk.Tk() - root.title("Robot Starting Position") - - label = tk.Label(root, text="Choose starting position") - label.pack(side="top", fill="none", expand=True) - selected = [start_positions[0]] - for pos in start_positions: - name = pos['name'] - button = tk.Button(root, text=name, command=_get_pos_callback(pos, root, selected)) - button.pack(side="top", fill="both", expand=True) - root.mainloop() - selected = selected[0] - - config_obj['pyfrc']['robot']['starting_x'] = selected['x'] - config_obj['pyfrc']['robot']['starting_y'] = selected['y'] - config_obj['pyfrc']['robot']['starting_angle'] = selected['angle'] - - -class SimUI(object): - - def __init__(self, manager, fake_time, config_obj): - ''' - initializes all default values and creates - a board, waits for run() to be called - to start the board - - manager - sim manager class instance - ''' - - self.manager = manager - self.fake_time = fake_time - self.config_obj = config_obj - - # Set up idle_add - self.queue = queue.Queue() - - self.root = tk.Tk() - self.root.wm_title("PyFRC Robot Simulator v%s" % __version__) - - # setup mode switch - frame = tk.Frame(self.root) - frame.pack(side=tk.TOP, anchor=tk.W) - - self._setup_widgets(frame) - - self.root.resizable(width=0, height=0) - - # Allow extending the simulation from 3rd party libraries - # -> TODO: better API for this - self.extensions = [] - for ep in iter_entry_points(group='robotpysim', name=None): - try: - extension = ep.load() - except ImportError: - logger.debug("Error importing extension '%s'", ep.name, exc_info=True) - else: - logger.debug("Loaded simulation extension '%s'", ep.name) - extension = extension() - - if hasattr(extension, 'update_tk_widgets'): - self.extensions.append(extension) - - self.mode_start_tm = 0 - self.text_id = None - - # connect to the controller - self.manager.on_mode_change(lambda mode: self.idle_add(self.on_robot_mode_change, mode)) - self.on_robot_mode_change(self.manager.get_mode()) - - # create pygame joystick if supported - try: - from pyfrc.sim.pygame_joysticks import UsbJoysticks - except ImportError: - logger.warn('pygame not detected, real joystick support not loaded') - self.usb_joysticks = None - else: - self.usb_joysticks = UsbJoysticks(self) - logger.info('pygame was detected, real joystick support loaded!') - - try: - self.root.lift() - self.root.attributes('-topmost', True) - self.root.attributes('-topmost', False) - except Exception: - pass - - self.timer_fired() - - def _setup_widgets(self, frame): - - top = tk.Frame(frame) - top.grid(column=0, row=0) - - bottom = tk.Frame(frame) - bottom.grid(column=0, row=1) - - self.field = RobotField(frame, self.manager, self.config_obj) - self.field.grid(column=1, row=0, rowspan=2) - - # status bar - self.status = tk.Label(frame, bd=1, relief=tk.SUNKEN, anchor=tk.E) - self.status.grid(column=0, row=2, columnspan=2, sticky=tk.W+tk.E) - - # analog - slot = tk.LabelFrame(top, text='Analog') - self.analog = [] - - for i in range(len(hal_data['analog_in'])): - if hal_data['analog_in'][i]['initialized'] or hal_data['analog_out'][i]['initialized']: - label = tk.Label(slot, text=str(i)) - label.grid(column=0, row=i+1) - - vw = ValueWidget(slot, clickable=True, minval=-10.0, maxval=10.0) - vw.grid(column=1, row=i+1) - self.set_tooltip(vw, 'analog', i) - else: - vw = None - - self.analog.append(vw) - - - slot.pack(side=tk.LEFT, fill=tk.Y, padx=5) - - # digital - slot = tk.LabelFrame(top, text='Digital') - - label = tk.Label(slot, text='PWM') - label.grid(column=0, columnspan=4, row=0) - self.pwm = [] - - for i in range(len(hal_data['pwm'])): - if hal_data['pwm'][i]['initialized']: - c = i // 10 - - label = tk.Label(slot, text=str(i)) - label.grid(column=0+2*c, row=1 + i % 10) - - vw = ValueWidget(slot) - vw.grid(column=1+2*c, row=1 + i % 10) - self.set_tooltip(vw, 'pwm', i) - else: - vw = None - self.pwm.append(vw) - - label = tk.Label(slot, text='Digital I/O') - label.grid(column=4, columnspan=6, row=0) - self.dio = [] - - for i in range(len(hal_data['dio'])): - - if hal_data['dio'][i]['initialized']: - - c = i // 9 - - label = tk.Label(slot, text=str(i)) - label.grid(column=4+c*2, row=1 + i % 9) - - pi = PanelIndicator(slot, clickable=True) - pi.grid(column=5+c*2, row=1 + i % 9) - self.set_tooltip(pi, 'dio', i) - else: - pi = None - - self.dio.append(pi) - - label = tk.Label(slot, text='Relay') - label.grid(column=10, columnspan=2, row=0, padx=5) - self.relays = [] - - for i in range(len(hal_data['relay'])): - if hal_data['relay'][i]['initialized']: - label = tk.Label(slot, text=str(i)) - label.grid(column=10, row=1 + i, sticky=tk.E) - - pi = PanelIndicator(slot) - pi.grid(column=11, row=1 + i) - self.set_tooltip(pi, 'relay', i) - else: - pi = None - - self.relays.append(pi) - - - slot.pack(side=tk.LEFT, fill=tk.Y, padx=5) - - self.csfm = csfm = tk.Frame(top) - - # solenoid (pcm) - self.pcm = {} - - # values - self.values = {} - - # CAN - self.can_slot = tk.LabelFrame(csfm, text='CAN') - self.can_slot.pack(side=tk.LEFT, fill=tk.BOTH, expand=1, padx=5) - self.can = {} - - csfm.pack(side=tk.LEFT, fill=tk.Y) - - # joysticks - slot = tk.LabelFrame(bottom, text='Joysticks') - - self.joysticks = [] - - for i in range(4): - - axes = [] - buttons = [] - - col = 1 + i*3 - row = 0 - - label = tk.Label(slot, text='Stick %s' % i) - label.grid(column=col, columnspan=3, row=row) - row += 1 - - # TODO: make this configurable - - for j, t in enumerate(['LX', 'LY', 'LT', 'RY', 'RX', 'RT']): - label = tk.Label(slot, text=t) - label.grid(column=col, row=row) - - vw = ValueWidget(slot, clickable=True, default=0.0) - vw.grid(column=col+1, row=row, columnspan=2) - self.set_joy_tooltip(vw, i, 'axes', t) - - axes.append(vw) - row += 1 - - # POV: this needs improvement - label = tk.Label(slot, text='POV') - label.grid(column=col, row=row) - pov = ValueWidget(slot, clickable=True, default=-1, minval=-1, maxval=360, step=45, round_to_step=True) - pov.grid(column=col+1, row=row, columnspan=2) - row += 1 - - for j in range(1, 11): - var = tk.IntVar() - ck = tk.Checkbutton(slot, text=str(j), variable=var) - ck.grid(column=col+1+(1-j%2), row=row + int((j - 1) / 2)) - self.set_joy_tooltip(ck, i, 'buttons', j) - - buttons.append((ck, var)) - - self.joysticks.append((axes, buttons, [pov])) - - - slot.pack(side=tk.LEFT, fill=tk.Y, padx=5) - - - ctrl_frame = tk.Frame(bottom) - - # timing control - timing_control = tk.LabelFrame(ctrl_frame, text='Time') - - def _set_realtime(): - if realtime_mode.get() == 0: - step_button.pack_forget() - step_entry.pack_forget() - self.on_pause(False) - else: - step_button.pack(fill=tk.X) - step_entry.pack() - self.on_pause(True) - - - realtime_mode = tk.IntVar() - - button = tk.Radiobutton(timing_control, text='Run', variable=realtime_mode, - value=0, command=_set_realtime) - button.pack(fill=tk.X) - - button = tk.Radiobutton(timing_control, text='Pause', variable=realtime_mode, - value=1, command=_set_realtime) - button.pack(fill=tk.X) - - step_button = tk.Button(timing_control, text='Step', command=self.on_step_time) - self.step_entry = tk.StringVar() - self.step_entry.set("0.025") - step_entry = tk.Entry(timing_control, width=6, textvariable=self.step_entry) - - Tooltip.create(step_button, 'Click this to increment time by the step value') - Tooltip.create(step_entry, 'Time to step (in seconds)') - realtime_mode.set(0) - - timing_control.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - - # simulation control - sim = tk.LabelFrame(ctrl_frame, text='Robot') - self.state_buttons = [] - - self.mode = tk.IntVar() - - def _set_mode(): - self.manager.set_mode(self.mode.get()) - - button = tk.Radiobutton(sim, text='Disabled', variable=self.mode, \ - value=self.manager.MODE_DISABLED, command=_set_mode) - button.pack(fill=tk.X) - self.state_buttons.append(button) - - button = tk.Radiobutton(sim, text='Autonomous', variable=self.mode, \ - value=self.manager.MODE_AUTONOMOUS, command=_set_mode) - button.pack(fill=tk.X) - self.state_buttons.append(button) - - button = tk.Radiobutton(sim, text='Teleoperated', variable=self.mode, \ - value=self.manager.MODE_OPERATOR_CONTROL, command=_set_mode) - button.pack(fill=tk.X) - self.state_buttons.append(button) - - button = tk.Radiobutton(sim, text='Test', variable=self.mode, \ - value=self.manager.MODE_TEST, command=_set_mode) - button.pack(fill=tk.X) - self.state_buttons.append(button) - - self.robot_dead = tk.Label(sim, text='Robot died!', fg='red') - - sim.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - - # - # Set up a combo box that allows you to select an autonomous - # mode in the simulator - # - - try: - from tkinter.ttk import Combobox - except: - pass - else: - auton = tk.LabelFrame(ctrl_frame, text='Autonomous') - - self.autobox = Combobox(auton, state='readonly') - self.autobox.bind('<>', self.on_auton_selected) - self.autobox['width'] = 12 - self.autobox.pack(fill=tk.X) - - Tooltip.create(self.autobox, "Use robotpy_ext.autonomous.AutonomousModeSelector to use this selection box") - - from networktables.util import ChooserControl - self.auton_ctrl = ChooserControl('Autonomous Mode', - lambda v: self.idle_add(self.on_auton_choices, v), - lambda v: self.idle_add(self.on_auton_selection, v)) - - auton.pack(side=tk.TOP) - - gamedata = tk.LabelFrame(ctrl_frame, text='Game Data') - - self.gamedataval = tk.StringVar() - if hasattr(self.gamedataval, 'trace_add'): - self.gamedataval.trace_add('write', self.on_gamedata_selected) - else: - self.gamedataval.trace_variable('w', self.on_gamedata_selected) - - self.gamedatabox = Combobox(gamedata, textvariable=self.gamedataval) - self.gamedatabox['width'] = 12 - self.gamedatabox.pack(fill=tk.X) - - messages = self.config_obj['pyfrc']['game_specific_messages'] - if messages: - self.gamedatabox['values'] = messages - self.gamedatabox.current(0) - - self.manager.game_specific_message = self.gamedatabox.get() - - Tooltip.create(self.gamedatabox, "Use this selection box to simulate game specific data") - gamedata.pack(side=tk.TOP) - - ctrl_frame.pack(side=tk.LEFT, fill=tk.Y) - - def _render_pcm(self): - - for k, data in sorted(hal_data['pcm'].items()): - if k not in self.pcm: - slot = tk.LabelFrame(self.csfm, text='Solenoid (PCM %s)' % k) - solenoids = [] - self.pcm[k] = solenoids - - for i in range(len(data)): - label = tk.Label(slot, text=str(i)) - - c = int(i/2)*2 - r = i%2 - - label.grid(column=0+c, row=r) - - pi = PanelIndicator(slot) - pi.grid(column=1+c, row=r) - self.set_tooltip(pi, 'solenoid', i) - - solenoids.append(pi) - - slot.pack(side=tk.TOP, fill=tk.BOTH, padx=5) - - solenoids = self.pcm[k] - for i, ch in enumerate(data): - sol = solenoids[i] - if not ch['initialized']: - sol.set_disabled() - else: - sol.set_value(ch['value']) - - def _render_values(self): - for k, v in hal_data['robot'].items(): - if not k.endswith('_angle'): - continue - gyro_label = self.values.get(k) - if not gyro_label: - gyro_label = self._create_value(k, k, 'Angle (Degrees)') - gyro_label['text'] = '%.3f' % v - - for i, gyro in enumerate(hal_data['analog_gyro']): - if not gyro['initialized']: - continue - k = 'Gyro %s' % i - gyro_label = self.values.get(k) - if not gyro_label: - gyro_label = self._create_value(k, k, 'Angle (Degrees)') - gyro_label['text'] = '%.3f' % gyro['angle'] - - for i, encoder in enumerate(hal_data['encoder']): - if not encoder['initialized']: - continue - k = 'Encoder %s' % i - label = self.values.get(k) - if not label: - txt = 'Encoder (%s,%s)' % (encoder['config']['ASource_Channel'], encoder['config']['BSource_Channel']) - label = self._create_value(k, txt, 'Count / Distance') - label['text'] = '%s / %.3f' % (encoder['count'], encoder['count']*encoder['distance_per_pulse']) - - for k, v in hal_data.get('custom', {}).items(): - label = self.values.get(k) - if not label: - label = self._create_value(k, k, k) - if isinstance(v, float): - label['text'] = '%.3f' % v - else: - label['text'] = str(v) - - def _create_value(self, key, text, tooltip): - slot = tk.LabelFrame(self.csfm, text=text) - label = tk.Label(slot) - label.pack(side=tk.TOP, fill=tk.BOTH) - slot.pack(side=tk.TOP, fill=tk.BOTH, padx=5) - self.values[key] = label - Tooltip.create(label, tooltip) - return label - - def idle_add(self, callable, *args): - '''Call this with a function as the argument, and that function - will be called on the GUI thread via an event - - This function returns immediately - ''' - self.queue.put((callable, args)) - - def __process_idle_events(self): - '''This should never be called directly, it is called via an - event, and should always be on the GUI thread''' - while True: - try: - callable, args = self.queue.get(block=False) - except queue.Empty: - break - callable(*args) - - def run(self): - # and launch the thread - self.root.mainloop() # This call BLOCKS - - def timer_fired(self): - '''Polling loop for events from other threads''' - self.__process_idle_events() - - # grab the simulation lock, gather all of the - # wpilib objects, and display them on the screen - self.update_widgets() - - # call next timer_fired (or we'll never call timer_fired again!) - delay = 100 # milliseconds - self.root.after(delay, self.timer_fired) # pause, then call timer_fired again - - - def update_widgets(self): - - # TODO: support multiple slots? - - #joystick stuff - if self.usb_joysticks is not None: - self.usb_joysticks.update() - - # analog module - for i, (ain, aout) in enumerate(zip(hal_data['analog_in'], - hal_data['analog_out'])): - - aio = self.analog[i] - if aio is not None: - if ain['initialized']: - aio.set_disabled(False) - ain['voltage'] = aio.get_value() - elif aout['initialized']: - aio.set_value(aout['voltage']) - - # digital module - for i, ch in enumerate(hal_data['dio']): - dio = self.dio[i] - if dio is not None: - if not ch['initialized']: - dio.set_disabled() - else: - # determine which one changed, and set the appropriate one - ret = dio.sync_value(ch['value']) - if ret is not None: - ch['value'] = ret - - for i, ch in enumerate(hal_data['pwm']): - pwm = self.pwm[i] - if pwm is not None: - pwm.set_value(ch['value']) - - for i, ch in enumerate(hal_data['relay']): - relay = self.relays[i] - if relay is not None: - if ch['fwd']: - relay.set_on() - elif ch['rev']: - relay.set_back() - else: - relay.set_off() - - # solenoid - self._render_pcm() - - # gyro/encoder - self._render_values() - - # joystick/driver station - #sticks = _core.DriverStation.GetInstance().sticks - #stick_buttons = _core.DriverStation.GetInstance().stick_buttons - - for i, (axes, buttons, povs) in enumerate(self.joysticks): - joy = hal_data['joysticks'][i] - jaxes = joy['axes'] - for j, ax in enumerate(axes): - jaxes[j] = ax.get_value() - - jbuttons = joy['buttons'] - for j, (ck, var) in enumerate(buttons): - jbuttons[j+1] = True if var.get() else False - - jpovs = joy['povs'] - for j, pov in enumerate(povs): - jpovs[j] = int(pov.get_value()) - - for extension in self.extensions: - extension.update_tk_widgets(self) - - self.field.update_widgets() - - tm = self.fake_time.get() - mode_tm = tm - self.mode_start_tm - - self.status.config(text="Time: %.03f mode, %.03f total" % (mode_tm, tm)) - - - - def set_tooltip(self, widget, cat, idx): - - tooltip = self.config_obj['pyfrc'][cat].get(str(idx)) - if tooltip is not None: - Tooltip.create(widget, tooltip) - - def set_joy_tooltip(self, widget, idx, typ, idx2): - tooltip = self.config_obj['pyfrc']['joysticks'][str(idx)][typ].get(str(idx2)) - if tooltip is not None: - Tooltip.create(widget, tooltip) - - def on_auton_choices(self, choices): - self.autobox['values'] = choices[:] - - def on_auton_selection(self, selection): - self.autobox.set(selection) - - def on_auton_selected(self, e): - self.auton_ctrl.setSelected(self.autobox.get()) - - def on_gamedata_selected(self, *args): - self.manager.game_specific_message = self.gamedatabox.get() - - def on_robot_mode_change(self, mode): - self.mode.set(mode) - - self.mode_start_tm = self.fake_time.get() - - # this is not strictly true... a robot can actually receive joystick - # commands from the driver station in disabled mode. However, most - # people aren't going to use that functionality... - controls_disabled = False if mode == self.manager.MODE_OPERATOR_CONTROL else True - state = tk.DISABLED if controls_disabled else tk.NORMAL - - for axes, buttons, povs in self.joysticks: - for axis in axes: - axis.set_disabled(disabled=controls_disabled) - for ck, var in buttons: - ck.config(state=state) - for pov in povs: - pov.set_disabled(disabled=controls_disabled) - - if not self.manager.is_alive(): - for button in self.state_buttons: - button.config(state=tk.DISABLED) - - self.robot_dead.pack() - - # - # Time related callbacks - # - - def on_pause(self, pause): - if pause: - self.fake_time.pause() - else: - self.fake_time.resume() - - def on_step_time(self): - val = self.step_entry.get() - try: - tm = float(self.step_entry.get()) - except ValueError: - tk.messagebox.showerror("Invalid step time", "'%s' is not a valid number" % val) - return - - if tm > 0: - self.fake_time.resume(tm)