def getTable(cls) -> NetworkTable: if cls.table is None: from networktables import NetworkTables cls.table = NetworkTables.getTable("SmartDashboard") hal.report(hal.UsageReporting.kResourceType_SmartDashboard, 0) return cls.table
def __init__(self, channel: int) -> None: """Allocate a PWM given a channel. :param channel: The PWM channel number. 0-9 are on-board, 10-19 are on the MXP port """ super().__init__() SendableBase.__init__(self) SensorUtil.checkPWMChannel(channel) self.channel = channel self.handle = hal.initializePWMPort(hal.getPort(channel)) self.__finalizer = weakref.finalize(self, _freePWM, self.handle) self.setDisabled() hal.setPWMEliminateDeadband(self.handle, False) hal.report(hal.UsageReporting.kResourceType_PWM, channel) self.setName("PWM", channel) self.setSafetyEnabled(False) # Python-specific: Need this to free on unit test wpilib reset Resource._add_global_resource(self)
def drivePolar(self, magnitude: float, angle: float, zRotation: float) -> None: """Drive method for Mecanum platform. Angles are measured counter-clockwise from straight ahead. The speed at which the robot drives (translation) is independent from its angle or rotation rate. :param magnitude: The robot's speed at a given angle [-1.0..1.0]. Forward is positive. :param angle: The angle around the Z axis at which the robot drives in degrees [-180..180]. :param zRotation: The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is positive. """ if not self.reported: hal.report( hal.UsageReporting.kResourceType_RobotDrive, 4, hal.UsageReporting.kRobotDrive2_MecanumPolar, ) self.reported = True magnitude = RobotDriveBase.limit(magnitude) * math.sqrt(2) self.driveCartesian( magnitude * math.cos(math.radians(angle)), magnitude * math.sin(math.radians(angle)), zRotation, 0.0, )
def __init__(self, port, range): """Constructor. Use this when the device is the first/only device on the bus :param port: The SPI port that the accelerometer is connected to :type port: :class:`.SPI.Port` :param range: The range (+ or -) that the accelerometer will measure. :type range: :class:`.ADXL345_SPI.Range` """ self.spi = SPI(port) self.spi.setClockRate(500000) self.spi.setMSBFirst() self.spi.setSampleDataOnTrailingEdge() self.spi.setClockActiveLow() self.spi.setChipSelectActiveHigh() # Turn on the measurements self.spi.write([self.kPowerCtlRegister, self.kPowerCtl_Measure]) self.setRange(range) hal.report(hal.UsageReporting.kResourceType_ADXL345, hal.UsageReporting.kADXL345_SPI) self.setName("ADXL345_SPI", port)
def __init__(self): RobotBase.__init__(self) self.iterator = None self.earlyStop = False hal.report(hal.UsageReporting.kResourceType_Framework, hal.UsageReporting.kFramework_Iterative)
def tankDrive(self, left, right, squaredInputs=True): """Provide tank steering using the stored robot configuration. :param left: The value to use for the left side motors. [-1.0..1.0] :param right: The value to use for the right side motors. [-1.0..1.0] :param squaredInputs: If set, decreases the input sensitivity at low speeds """ if not self.reported: hal.report(hal.UsageReporting.kResourceType_RobotDrive, 2, hal.UsageReporting.kRobotDrive_Tank) self.reported = True left = RobotDriveBase.limit(left) left = RobotDriveBase.applyDeadband(left, self.deadband) right = RobotDriveBase.limit(right) right = RobotDriveBase.applyDeadband(right, self.deadband) # square the inputs (while preserving the sign) to increase fine # control while permitting full power if squaredInputs: left = math.copysign(left * left, left) right = math.copysign(right * right, right) self.leftMotor.set(left * self.maxOutput) self.rightMotor.set(-right * self.maxOutput) self.feed()
def _initRelay(self) -> None: SensorUtil.checkRelayChannel(self.channel) portHandle = hal.getPort(self.channel) try: if ( self.direction == self.Direction.kBoth or self.direction == self.Direction.kForward ): Relay.relayChannels.allocate(self, self.channel * 2) self._forwardHandle = hal.initializeRelayPort(portHandle, True) hal.report(hal.UsageReporting.kResourceType_Relay, self.channel) if ( self.direction == self.Direction.kBoth or self.direction == self.Direction.kReverse ): Relay.relayChannels.allocate(self, self.channel * 2 + 1) self._reverseHandle = hal.initializeRelayPort(portHandle, False) hal.report(hal.UsageReporting.kResourceType_Relay, self.channel + 128) except IndexError as e: raise IndexError( "Relay channel %d is already allocated" % self.channel ) from e self.__finalizer = weakref.finalize( self, _freeRelay, self._forwardHandle, self._reverseHandle ) self.setSafetyEnabled(False) self.setName("Relay", self.channel)
def __init__(self, port): """Construct an instance of a joystick. The joystick index is the USB port on the Driver Station. This constructor is intended for use by subclasses to configure the number of constants for axes and buttons. :param port: The port on the Driver Station that the joystick is plugged into. :type port: int :param numAxisTypes: The number of axis types. :type numAxisTypes: int :param numButtonTypes: The number of button types. :type numButtonTypes: int """ super().__init__(port) from .driverstation import DriverStation self.ds = DriverStation.getInstance() self.axes = [0] * self.Axis.kNumAxis self.axes[self.Axis.kX] = self.kDefaultXAxis self.axes[self.Axis.kY] = self.kDefaultYAxis self.axes[self.Axis.kZ] = self.kDefaultZAxis self.axes[self.Axis.kTwist] = self.kDefaultTwistAxis self.axes[self.Axis.kThrottle] = self.kDefaultThrottleAxis self.outputs = 0 self.leftRumble = 0 self.rightRumble = 0 hal.report(hal.UsageReporting.kResourceType_Joystick, port)
def __init__(self, channel: int, directionSensitive: bool = False) -> None: """Construct a GearTooth sensor. :param channel: The DIO channel index or DigitalSource that the sensor is connected to. :param directionSensitive: True to enable the pulse length decoding in hardware to specify count direction. Defaults to False. """ super().__init__(channel) self.enableDirectionSensing(directionSensitive) if hasattr(self.upSource, "getChannel"): if directionSensitive: hal.report( hal.UsageReporting.kResourceType_GearTooth, self.upSource.getChannel(), 0, "D", ) else: hal.report( hal.UsageReporting.kResourceType_GearTooth, self.upSource.getChannel(), 0, ) self.setName("GearTooth", self.upSource.getChannel())
def _initRelay(self) -> None: SensorUtil.checkRelayChannel(self.channel) portHandle = hal.getPort(self.channel) try: if ( self.direction == self.Direction.kBoth or self.direction == self.Direction.kForward ): Relay.relayChannels.allocate(self, self.channel * 2) self.forwardHandle = hal.initializeRelayPort(portHandle, True) hal.report(hal.UsageReporting.kResourceType_Relay, self.channel) if ( self.direction == self.Direction.kBoth or self.direction == self.Direction.kReverse ): Relay.relayChannels.allocate(self, self.channel * 2 + 1) self.reverseHandle = hal.initializeRelayPort(portHandle, False) hal.report(hal.UsageReporting.kResourceType_Relay, self.channel + 128) except IndexError as e: raise IndexError( "Relay channel %d is already allocated" % self.channel ) from e self.__finalizer = weakref.finalize( self, _freeRelay, self.forwardHandle, self.reverseHandle ) self.setSafetyEnabled(False) self.setName("Relay", self.channel)
def __init__(self, channel): """Constructor. :param channel: The PWM channel that the SPARK is attached to. 0-9 are on-board, 10-19 are on the MXP port .. note :: Note that the SD540 uses the following bounds for PWM values. These values should work reasonably well for most controllers, but if users experience issues such as asymmetric behavior around the deadband or inability to saturate the controller in either direction, calibration is recommended. The calibration procedure can be found in the SD540 User Manual available from Mindsensors. - 2.003ms = full "forward" - 1.55ms = the "high end" of the deadband range - 1.50ms = center of the deadband range (off) - 1.46ms = the "low end" of the deadband range - .999ms = full "reverse" """ super().__init__(channel) self.setBounds(2.003, 1.55, 1.50, 1.46, .999) self.setPeriodMultiplier(self.PeriodMultiplier.k1X) self.setSpeed(0) self.setZeroLatch() hal.report(hal.UsageReporting.kResourceType_RevSPARK, self.getChannel()) self.setName("Spark", self.getChannel())
def __init__(self, channel): """Constructor for an analog trigger given a channel number or analog input. :param channel: the port index or :class:`.AnalogInput` to use for the analog trigger. Treated as an AnalogInput if the provided object has a getChannel function. """ super().__init__() if not hasattr(channel, "getChannel"): self.analogInput = AnalogInput(channel) self.ownsAnalog = True self.addChild(self.analogInput) else: self.analogInput = channel self._port, self.index = hal.initializeAnalogTrigger( self.analogInput.port) self.__finalizer = \ weakref.finalize(self, _freeAnalogTrigger, self._port) # Need this to free on unit test wpilib reset Resource._add_global_resource(self) hal.report(hal.UsageReporting.kResourceType_AnalogTrigger, channel) self.setName("AnalogTrigger", self.analogInput.getChannel())
def __init__(self, channel: int) -> None: """Allocate a PWM given a channel. :param channel: The PWM channel number. 0-9 are on-board, 10-19 are on the MXP port """ super().__init__() SendableBase.__init__(self) SensorUtil.checkPWMChannel(channel) self.channel = channel self._handle = hal.initializePWMPort(hal.getPort(channel)) self.__finalizer = weakref.finalize(self, _freePWM, self._handle) self.setDisabled() hal.setPWMEliminateDeadband(self.handle, False) hal.report(hal.UsageReporting.kResourceType_PWM, channel) self.setName("PWM", channel) self.setSafetyEnabled(False) # Python-specific: Need this to free on unit test wpilib reset Resource._add_global_resource(self)
def getTable(cls): if cls.table is None: from networktables import NetworkTable cls.table = NetworkTable.getTable("SmartDashboard") hal.report(hal.UsageReporting.kResourceType_SmartDashboard, hal.UsageReporting.kSmartDashboard_Instance) return cls.table
def __init__(self, channel: int) -> None: """Constructor for a TalonSRX connected via PWM. :param channel: The PWM channel that the PWMTalonSRX is attached to. 0-9 are on-board, 10-19 are on the MXP port. .. note :: The PWMTalonSRX uses the following bounds for PWM values. These values should work reasonably well for most controllers, but if users experience issues such as asymmetric behavior around the deadband or inability to saturate the controller in either direction, calibration is recommended. The calibration procedure can be found in the TalonSRX User Manual available from CTRE. - 2.004ms = full "forward" - 1.520ms = the "high end" of the deadband range - 1.500ms = center of the deadband range (off) - 1.480ms = the "low end" of the deadband range - 0.997ms = full "reverse" """ super().__init__(channel) self.setBounds(2.004, 1.52, 1.50, 1.48, 0.997) self.setPeriodMultiplier(self.PeriodMultiplier.k1X) self.setSpeed(0) self.setZeroLatch() hal.report(hal.UsageReporting.kResourceType_PWMTalonSRX, self.getChannel()) self.setName("PWMTalonSRX", self.getChannel())
def __init__(self, channel): """Constructor for a Talon (original or Talon SR) :param channel: The PWM channel that the Talon is attached to. 0-9 are on-board, 10-19 are on the MXP port :type channel: int .. note :: The Talon uses the following bounds for PWM values. These values should work reasonably well for most controllers, but if users experience issues such as asymmetric behavior around the deadband or inability to saturate the controller in either direction, calibration is recommended. The calibration procedure can be found in the Talon User Manual available from CTRE. - 2.037ms = full "forward" - 1.539ms = the "high end" of the deadband range - 1.513ms = center of the deadband range (off) - 1.487ms = the "low end" of the deadband range - 0.989ms = full "reverse" """ super().__init__(channel) self.setBounds(2.037, 1.539, 1.513, 1.487, 0.989) self.setPeriodMultiplier(self.PeriodMultiplier.k1X) self.setSpeed(0.0) self.setZeroLatch() hal.report(hal.UsageReporting.kResourceType_Talon, self.getChannel()) self.setName("Talon", self.getChannel())
def __init__(self): super().__init__() hal.report(hal.UsageReporting.kResourceType_Framework, hal.UsageReporting.kFramework_Iterative) self._loop = asyncio.get_event_loop() self._active_commands = []
def __init__(self): """Creates a preference class that will automatically read the file in a different thread. Any call to its methods will be blocked until the thread is finished reading. """ # The actual values (str->str) self.values = {} # The keys in the order they were read from the file self.keylist = [] # The comments that were in the file sorted by which key they appeared # over (str->str) self.comments = {} # The comment at the end of the file self.endComment = "" # The semaphore for beginning reads and writes to the file self.fileLock = threading.Condition() # The semaphore for reading from the table self.lock = threading.RLock() # We synchronized on fileLock and then wait # for it to know that the reading thread has started with self.fileLock: reader = threading.Thread(target=self._read, name="Preferences Read") reader.start() self.fileLock.wait() hal.report(hal.UsageReporting.kResourceType_Preferences, 0)
def __init__(self, channel): """Constructor. :param channel: The PWM channel that the SPARK is attached to. 0-9 are on-board, 10-19 are on the MXP port .. note :: Note that the SD540 uses the following bounds for PWM values. These values should work reasonably well for most controllers, but if users experience issues such as asymmetric behavior around the deadband or inability to saturate the controller in either direction, calibration is recommended. The calibration procedure can be found in the SD540 User Manual available from Mindsensors. - 2.003ms = full "forward" - 1.55ms = the "high end" of the deadband range - 1.50ms = center of the deadband range (off) - 1.46ms = the "low end" of the deadband range - .999ms = full "reverse" """ super().__init__(channel) self.setBounds(2.003, 1.55, 1.50, 1.46, .999) self.setPeriodMultiplier(self.PeriodMultiplier.k1X) self.setSpeed(0) self.setZeroLatch() LiveWindow.addActuatorChannel("Spark", self.getChannel(), self) hal.report(hal.UsageReporting.kResourceType_RevSPARK, self.getChannel())
def __init__(self, channel): """Constructor. :param channel: The PWM channel that the VictorSP is attached to. 0-9 are on-board, 10-19 are on the MXP port. :type channel: int .. note :: The Talon uses the following bounds for PWM values. These values should work reasonably well for most controllers, but if users experience issues such as asymmetric behavior around the deadband or inability to saturate the controller in either direction, calibration is recommended. The calibration procedure can be found in the VictorSP User Manual. - 2.004ms = full "forward" - 1.520ms = the "high end" of the deadband range - 1.500ms = center of the deadband range (off) - 1.480ms = the "low end" of the deadband range - 0.997ms = full "reverse" """ super().__init__(channel) self.setBounds(2.004, 1.52, 1.50, 1.48, .997) self.setPeriodMultiplier(self.PeriodMultiplier.k1X) self.setSpeed(0) self.setZeroLatch() LiveWindow.addActuatorChannel("VictorSP", self.getChannel(), self) hal.report(hal.UsageReporting.kResourceType_VictorSP, self.getChannel())
def __init__(self, *args, **kwargs): """ Arguments can be structured as follows: - deviceNumber - talonSrx :param deviceNumber: CAN Device Id of Pigeon [0,62] :param talonSrx: Object for the TalonSRX connected via ribbon cable. """ super().__init__() deviceNumber_arg = ("deviceNumber", [int]) talonSrx_arg = ("talonSrx", [TalonSRX]) templates = [[deviceNumber_arg], [talonSrx_arg]] index, results = match_arglist('PigeonIMU.__init__', args, kwargs, templates) self.generalStatus = [0] * 10 self.fusionStatus = [0] * 10 if index == 0: self.deviceNumber = results['deviceNumber'] self._create1(self.deviceNumber) elif index == 1: self.deviceNumber = results['talonSrx'].getDeviceID() self._create2(self.deviceNumber) hal.report(64, self.deviceNumber + 1) hal.report(hal.UsageReporting.kResourceType_PigeonIMU, self.deviceNumber + 1)
def main(robot_cls): """Starting point for the applications.""" RobotBase.initializeHardwareConfiguration() hal.report(hal.UsageReporting.kResourceType_Language, hal.UsageReporting.kLanguage_Python) try: robot = robot_cls() except: from .driverstation import DriverStation DriverStation.reportError( "Unhandled exception instantiating robot " + robot_cls.__name__, True) DriverStation.reportWarning( "Robots should not quit, but yours did!", False) DriverStation.reportError( "Could not instantiate robot " + robot_cls.__name__ + "!", False) return False # Add a check to see if the user forgot to call super().__init__() if not hasattr(robot, '_RobotBase__initialized'): logger.error( "If your robot class has an __init__ function, it must call super().__init__()!" ) return False if not hal.isSimulation(): try: import wpilib with open('/tmp/frc_versions/FRC_Lib_Version.ini', 'w') as fp: fp.write('RobotPy %s' % wpilib.__version__) except: logger.warning("Could not write FRC version file to disk") try: robot.startCompetition() except KeyboardInterrupt: logger.exception( "THIS IS NOT AN ERROR: The user hit CTRL-C to kill the robot") logger.info("Exiting because of keyboard interrupt") return True except: from .driverstation import DriverStation DriverStation.reportError("Unhandled exception", True) DriverStation.reportWarning( "Robots should not quit, but yours did!", False) DriverStation.reportError( "The startCompetition() method (or methods called by it) should have handled the exception above.", False) return False else: # startCompetition never returns unless exception occurs.... from .driverstation import DriverStation DriverStation.reportWarning( "Robots should not quit, but yours did!", False) DriverStation.reportError( "Unexpected return from startCompetition() method.", False) return False
def __init__(self, port, range): """Constructor. Use this when the device is the first/only device on the bus :param port: The SPI port that the accelerometer is connected to :type port: :class:`.SPI.Port` :param range: The range (+ or -) that the accelerometer will measure. :type range: :class:`.ADXL345_SPI.Range` """ self.spi = SPI(port) self.spi.setClockRate(500000) self.spi.setMSBFirst() self.spi.setSampleDataOnFalling() self.spi.setClockActiveLow() self.spi.setChipSelectActiveHigh() # Turn on the measurements self.spi.write([self.kPowerCtlRegister, self.kPowerCtl_Measure]) self.setRange(range) hal.report(hal.UsageReporting.kResourceType_ADXL345, hal.UsageReporting.kADXL345_SPI) LiveWindow.addSensor("ADXL345_SPI", port, self)
def __init__(self, channel): """Constructor for a Talon (original or Talon SR) :param channel: The PWM channel that the Talon is attached to. 0-9 are on-board, 10-19 are on the MXP port :type channel: int .. note :: The Talon uses the following bounds for PWM values. These values should work reasonably well for most controllers, but if users experience issues such as asymmetric behavior around the deadband or inability to saturate the controller in either direction, calibration is recommended. The calibration procedure can be found in the Talon User Manual available from CTRE. - 2.037ms = full "forward" - 1.539ms = the "high end" of the deadband range - 1.513ms = center of the deadband range (off) - 1.487ms = the "low end" of the deadband range - 0.989ms = full "reverse" """ super().__init__(channel) self.setBounds(2.037, 1.539, 1.513, 1.487, 0.989) self.setPeriodMultiplier(self.PeriodMultiplier.k1X) self.setSpeed(0.0) self.setZeroLatch() LiveWindow.addActuatorChannel("Talon", self.getChannel(), self) hal.report(hal.UsageReporting.kResourceType_Talon, self.getChannel())
def tankDrive(self, leftSpeed, rightSpeed, squaredInputs=True): """Provide tank steering using the stored robot configuration. :param leftSpeed: The robot's left side speed along the X axis `[-1.0..1.0]`. Forward is positive. :param rightSpeed: The robot's right side speed along the X axis`[-1.0..1.0]`. Forward is positive. :param squaredInputs: If set, decreases the input sensitivity at low speeds """ if not self.reported: hal.report(hal.UsageReporting.kResourceType_RobotDrive, 2, hal.UsageReporting.kRobotDrive_Tank) self.reported = True leftSpeed = RobotDriveBase.limit(leftSpeed) leftSpeed = RobotDriveBase.applyDeadband(leftSpeed, self.deadband) rightSpeed = RobotDriveBase.limit(rightSpeed) rightSpeed = RobotDriveBase.applyDeadband(rightSpeed, self.deadband) # square the inputs (while preserving the sign) to increase fine # control while permitting full power if squaredInputs: leftSpeed = math.copysign(leftSpeed * leftSpeed, leftSpeed) rightSpeed = math.copysign(rightSpeed * rightSpeed, rightSpeed) self.leftMotor.set(leftSpeed * self.maxOutput) self.rightMotor.set(-rightSpeed * self.maxOutput) self.feed()
def __init__(self): """Instantiates a Scheduler. """ super().__init__() hal.report(hal.UsageReporting.kResourceType_Command, hal.UsageReporting.kCommand_Scheduler) self.setName("Scheduler") # Active Commands self.commandTable = collections.OrderedDict() # The set of all Subsystems self.subsystems = set() # Whether or not we are currently adding a command self.adding = False # Whether or not we are currently disabled self.disabled = False # A list of all Commands which need to be added self.additions = [] # A list of all Buttons. It is created lazily. self.buttons = [] self.runningCommandsChanged = False self.namesEntry = None self.idsEntry = None self.cancelEntry = None
def launch(cls, vision_py=None): """ Launches the CameraServer process in autocapture mode or using a user-specified python script :param vision_py: If specified, this is the relative path to a filename with a function in it Example usage:: wpilib.CameraServer.launch("vision.py:main") .. warning:: You must have robotpy-cscore installed, or this function will fail without returning an error (you will see an error in the console). """ if cls._launched: return cls._launched = True if hal.isSimulation(): logger.info("Would launch CameraServer with vision_py=%s", vision_py) cls._alive = True else: logger.info("Launching CameraServer process") # Launch the cscore launcher in a separate process import subprocess import sys args = [sys.executable, "-m", "cscore"] # TODO: Get accurate reporting data from the other cscore process. For # now, just differentiate between users with a custom py file and those # who do not. cscore handle values indicate type with bits 24-30 if vision_py: if not vision_py.startswith("/"): vision_py = "/home/lvuser/py/" + vision_py args.append(vision_py) hal.report(hal.UsageReporting.kResourceType_PCVideoServer, 0x51) else: hal.report(hal.UsageReporting.kResourceType_PCVideoServer, 0x52) # We open a pipe to it so that when this process exits, it dies proc = subprocess.Popen(args, close_fds=True, stdin=subprocess.PIPE, cwd="/home/lvuser/py") th = threading.Thread(target=cls._monitor_child, args=(proc, )) th.daemon = True th.start()
def __init__(self, port: int) -> None: """Construct an instance of an XBoxController. The XBoxController index is the USB port on the Driver Station. :param port: The port on the Driver Station that the joystick is plugged into """ super().__init__(port) hal.report(hal.UsageReporting.kResourceType_XboxController, port)
def __init__(self, *args, **kwargs): """Constructor. Arguments can be supplied as positional or keyword. Acceptable positional argument combinations are: - channel - moduleNumber, channel Alternatively, the above names can be used as keyword arguments. :param moduleNumber: The CAN ID of the PCM the solenoid is attached to :type moduleNumber: int :param channel: The channel on the PCM to control (0..7) :type channel: int """ # keyword arguments channel = kwargs.pop("channel", None) moduleNumber = kwargs.pop("moduleNumber", None) if kwargs: warnings.warn("unknown keyword arguments: %s" % kwargs.keys(), RuntimeWarning) # positional arguments if len(args) == 1: channel = args[0] elif len(args) == 2: moduleNumber, channel = args elif len(args) != 0: raise ValueError( "don't know how to handle %d positional arguments" % len(args)) if moduleNumber is None: moduleNumber = SensorBase.getDefaultSolenoidModule() if channel is None: raise ValueError("must specify channel") super().__init__(moduleNumber) self.channel = channel self.valueEntry = None SensorBase.checkSolenoidModule(moduleNumber) SensorBase.checkSolenoidChannel(channel) portHandle = hal.getPortWithModule(moduleNumber, channel) self._solenoidHandle = hal.initializeSolenoidPort(portHandle) LiveWindow.addActuatorModuleChannel("Solenoid", moduleNumber, channel, self) hal.report(hal.UsageReporting.kResourceType_Solenoid, channel, moduleNumber) self.__finalizer = weakref.finalize(self, _freeSolenoid, self._solenoidHandle) # Need this to free on unit test wpilib reset Resource._add_global_resource(self)
def __init__(self): super().__init__() hal.report(hal.UsageReporting.kResourceType_Framework, hal.UsageReporting.kFramework_Iterative) self.period = TimedRobot.DEFAULT_PERIOD # Prevents loop from starting if user calls setPeriod() in robotInit() self.startLoop = False self.loop = Notifier(self.loopFunc)
def __init__(self): """Creates a preference class that will automatically read the file in a different thread. Any call to its methods will be blocked until the thread is finished reading. """ self.table = NetworkTables.getTable(self.TABLE_NAME) self.table.addTableListenerEx(self.valueChangedEx, NetworkTables.NotifyFlags.NEW | NetworkTables.NotifyFlags.IMMEDIATE) hal.report(hal.UsageReporting.kResourceType_Preferences, 0)
def __init__(self, deviceNumber: int) -> None: """Constructor :param deviceNumber: [0,62] """ super().__init__(deviceNumber | 0x01040000) hal.report(hal.UsageReporting.kResourceType_CTRE_future1, deviceNumber + 1)
def __init__(self, module: int = 0) -> None: """ :param module: CAN ID of the PDP """ super().__init__() SensorUtil.checkPDPModule(module) self.handle = hal.initializePDP(module) hal.report(hal.UsageReporting.kResourceType_PDP, module) self.setName("PowerDistributionPanel", module)
def driveCartesian(self, ySpeed: float, xSpeed: float, zRotation: float, gyroAngle: float = 0.0) -> None: """Drive method for Mecanum platform. Angles are measured clockwise from the positive X axis. The robot's speed is independent from its angle or rotation rate. :param ySpeed: The robot's speed along the Y axis [-1.0..1.0]. Right is positive. :param xSpeed: The robot's speed along the X axis [-1.0..1.0]. Forward is positive. :param zRotation: The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is positive. :param gyroAngle: The current angle reading from the gyro in degrees around the Z axis. Use this to implement field-oriented controls. """ if not self.reported: hal.report( hal.UsageReporting.kResourceType_RobotDrive, 4, hal.UsageReporting.kRobotDrive2_MecanumCartesian, ) self.reported = True ySpeed = RobotDriveBase.limit(ySpeed) ySpeed = RobotDriveBase.applyDeadband(ySpeed, self.deadband) xSpeed = RobotDriveBase.limit(xSpeed) xSpeed = RobotDriveBase.applyDeadband(xSpeed, self.deadband) # Compensate for gyro angle input = Vector2d(ySpeed, xSpeed) input.rotate(gyroAngle) wheelSpeeds = [ # Front Left input.x + input.y + zRotation, # Rear Left -input.x + input.y + zRotation, # Front Right -input.x + input.y - zRotation, # Rear Right input.x + input.y - zRotation, ] RobotDriveBase.normalize(wheelSpeeds) wheelSpeeds = [speed * self.maxOutput for speed in wheelSpeeds] self.frontLeftMotor.set(wheelSpeeds[0]) self.rearLeftMotor.set(wheelSpeeds[1]) self.frontRightMotor.set(wheelSpeeds[2] * self.rightSideInvertMultiplier) self.rearRightMotor.set(wheelSpeeds[3] * self.rightSideInvertMultiplier) self.feed()
def __init__(self, *args, **kwargs): """Constructor. Arguments can be supplied as positional or keyword. Acceptable positional argument combinations are: - channel - moduleNumber, channel Alternatively, the above names can be used as keyword arguments. :param moduleNumber: The CAN ID of the PCM the solenoid is attached to :type moduleNumber: int :param channel: The channel on the PCM to control (0..7) :type channel: int """ # keyword arguments channel = kwargs.pop("channel", None) moduleNumber = kwargs.pop("moduleNumber", None) if kwargs: warnings.warn("unknown keyword arguments: %s" % kwargs.keys(), RuntimeWarning) # positional arguments if len(args) == 1: channel = args[0] elif len(args) == 2: moduleNumber, channel = args elif len(args) != 0: raise ValueError("don't know how to handle %d positional arguments" % len(args)) if moduleNumber is None: moduleNumber = SensorBase.getDefaultSolenoidModule() if channel is None: raise ValueError("must specify channel") SensorBase.checkSolenoidModule(moduleNumber) SensorBase.checkSolenoidChannel(channel) super().__init__(moduleNumber) self.channel = channel try: self.allocated.allocate(self, channel) except IndexError as e: raise IndexError("Solenoid channel %d on module %d is already allocated" % (channel, moduleNumber)) from e portHandle= hal.getPortWithModule(moduleNumber, channel) self._solenoidHandle = hal.initializeSolenoidPort(portHandle) LiveWindow.addActuatorModuleChannel("Solenoid", moduleNumber, channel, self) hal.report(hal.UsageReporting.kResourceType_Solenoid, channel, moduleNumber) self.__finalizer = weakref.finalize(self, _freeSolenoid, self._solenoidHandle)
def arcadeDrive(self, xSpeed: float, zRotation: float, squareInputs: bool = True) -> None: """Arcade drive method for differential drive platform. :param xSpeed: The robot's speed along the X axis `[-1.0..1.0]`. Forward is positive :param zRotation: The robot's zRotation rate around the Z axis `[-1.0..1.0]`. Clockwise is positive :param squareInputs: If set, decreases the sensitivity at low speeds. """ if not self.reported: hal.report( hal.UsageReporting.kResourceType_RobotDrive, 2, hal.UsageReporting.kRobotDrive_ArcadeStandard, ) self.reported = True xSpeed = RobotDriveBase.limit(xSpeed) xSpeed = RobotDriveBase.applyDeadband(xSpeed, self.deadband) zRotation = RobotDriveBase.limit(zRotation) zRotation = RobotDriveBase.applyDeadband(zRotation, self.deadband) if squareInputs: # Square the inputs (while preserving the sign) to increase fine # control while permitting full power. xSpeed = math.copysign(xSpeed * xSpeed, xSpeed) zRotation = math.copysign(zRotation * zRotation, zRotation) maxInput = math.copysign(max(abs(xSpeed), abs(zRotation)), xSpeed) if xSpeed >= 0.0: if zRotation >= 0.0: leftMotorSpeed = maxInput rightMotorSpeed = xSpeed - zRotation else: leftMotorSpeed = xSpeed + zRotation rightMotorSpeed = maxInput else: if zRotation >= 0.0: leftMotorSpeed = xSpeed + zRotation rightMotorSpeed = maxInput else: leftMotorSpeed = maxInput rightMotorSpeed = xSpeed - zRotation leftMotorSpeed = RobotDriveBase.limit(leftMotorSpeed) * self.maxOutput rightMotorSpeed = RobotDriveBase.limit( rightMotorSpeed) * self.maxOutput self.leftMotor.set(leftMotorSpeed) self.rightMotor.set(rightMotorSpeed * self.rightSideInvertMultiplier) self.feed()
def __init__(self, pingChannel, echoChannel, units=Unit.kInches): """Create an instance of the Ultrasonic Sensor. This is designed to supchannel the Daventech SRF04 and Vex ultrasonic sensors. :param pingChannel: The digital output channel that sends the pulse to initiate the sensor sending the ping. :param echoChannel: The digital input channel that receives the echo. The length of time that the echo is high represents the round trip time of the ping, and the distance. :param units: The units returned in either kInches or kMillimeters """ super().__init__() # Convert to DigitalInput and DigitalOutput if necessary self.pingAllocated = False self.echoAllocated = False if not hasattr(pingChannel, "channel"): from .digitaloutput import DigitalOutput pingChannel = DigitalOutput(pingChannel) self.pingAllocated = True if not hasattr(echoChannel, "channel"): from .digitalinput import DigitalInput echoChannel = DigitalInput(echoChannel) self.echoAllocated = True self.pingChannel = pingChannel self.echoChannel = echoChannel self.units = units self.pidSource = self.PIDSourceType.kDisplacement self.enabled = True # make it available for round robin scheduling self.valueEntry = None # set up counter for this sensor self.counter = Counter(self.echoChannel) self.counter.setMaxPeriod(1.0) self.counter.setSemiPeriodMode(True) self.counter.reset() isAutomatic = Ultrasonic.isAutomaticMode() self.setAutomaticMode(False) Ultrasonic.sensors.add(self) if isAutomatic: self.setAutomaticMode(True) Resource._add_global_resource(self) Ultrasonic.instances += 1 hal.report(hal.UsageReporting.kResourceType_Ultrasonic, Ultrasonic.instances) LiveWindow.addSensor("Ultrasonic", self.echoChannel.getChannel(), self)
def __init__( self, pingChannel: Union[DigitalOutput, int], echoChannel: Union[DigitalInput, int], units: Unit = Unit.kInches, ) -> None: """Create an instance of the Ultrasonic Sensor. This is designed to supchannel the Daventech SRF04 and Vex ultrasonic sensors. :param pingChannel: The digital output channel that sends the pulse to initiate the sensor sending the ping. :param echoChannel: The digital input channel that receives the echo. The length of time that the echo is high represents the round trip time of the ping, and the distance. :param units: The units returned in either kInches or kMillimeters """ super().__init__() # Convert to DigitalInput and DigitalOutput if necessary self.pingAllocated = False self.echoAllocated = False if not hasattr(pingChannel, "channel"): pingChannel = DigitalOutput(pingChannel) self.pingAllocated = True if not hasattr(echoChannel, "channel"): echoChannel = DigitalInput(echoChannel) self.echoAllocated = True self.pingChannel = pingChannel self.echoChannel = echoChannel self.units = units self.pidSource = self.PIDSourceType.kDisplacement self.enabled = True # make it available for round robin scheduling self.valueEntry = None # set up counter for this sensor self.counter = Counter(self.echoChannel) self.counter.setMaxPeriod(1.0) self.counter.setSemiPeriodMode(True) self.counter.reset() isAutomatic = Ultrasonic.isAutomaticMode() self.setAutomaticMode(False) Ultrasonic.sensors.add(self) if isAutomatic: self.setAutomaticMode(True) Resource._add_global_resource(self) Ultrasonic.instances += 1 hal.report(hal.UsageReporting.kResourceType_Ultrasonic, Ultrasonic.instances) self.setName("Ultrasonic", echoChannel.getChannel())
def __init__(self, port: Optional[SPI.Port] = None) -> None: """ Constructor. :param port: The SPI port that the gyro is connected to """ super().__init__() if port is None: port = SPI.Port.kOnboardCS0 simPort = None if hal.HALIsSimulation(): from hal_impl.spi_helpers import ADXRS450_Gyro_Sim simPort = ADXRS450_Gyro_Sim(self) self.spi = SPI(port, simPort=simPort) self.spi.setClockRate(3000000) self.spi.setMSBFirst() self.spi.setSampleDataOnLeadingEdge() self.spi.setClockActiveHigh() self.spi.setChipSelectActiveLow() # Validate the part ID if (self._readRegister(self.kPIDRegister) & 0xFF00) != 0x5200: self.spi.close() self.spi = None DriverStation.reportError( "could not find ADXRS450 gyro on SPI port %s" % port, False ) return # python-specific: make this easier to simulate if hal.isSimulation(): self.spi.initAccumulator( self.kSamplePeriod, 0x20000000, 4, 0x0, 0x0, 0, 32, True, True ) else: self.spi.initAccumulator( self.kSamplePeriod, 0x20000000, 4, 0x0C00000E, 0x04000000, 10, 16, True, True, ) self.calibrate() hal.report(hal.UsageReporting.kResourceType_ADXRS450, port) self.setName("ADXRS450_Gyro", port)
def __init__(self, *args, **kwargs) -> None: """Constructor. Arguments can be supplied as positional or keyword. Acceptable positional argument combinations are: - channel - moduleNumber, channel Alternatively, the above names can be used as keyword arguments. :param moduleNumber: The CAN ID of the PCM the solenoid is attached to :type moduleNumber: int :param channel: The channel on the PCM to control (0..7) :type channel: int """ # keyword arguments channel = kwargs.pop("channel", None) moduleNumber = kwargs.pop("moduleNumber", None) if kwargs: warnings.warn( "unknown keyword arguments: %s" % kwargs.keys(), RuntimeWarning ) # positional arguments if len(args) == 1: channel = args[0] elif len(args) == 2: moduleNumber, channel = args elif len(args) != 0: raise ValueError( "don't know how to handle %d positional arguments" % len(args) ) if moduleNumber is None: moduleNumber = SensorUtil.getDefaultSolenoidModule() if channel is None: raise ValueError("must specify channel") super().__init__(moduleNumber) self.channel = channel SensorUtil.checkSolenoidModule(moduleNumber) SensorUtil.checkSolenoidChannel(channel) portHandle = hal.getPortWithModule(moduleNumber, channel) self.solenoidHandle = hal.initializeSolenoidPort(portHandle) hal.report(hal.UsageReporting.kResourceType_Solenoid, channel, moduleNumber) self.setName("Solenoid", self.moduleNumber, self.channel) self.__finalizer = weakref.finalize(self, _freeSolenoid, self.solenoidHandle) # Need this to free on unit test wpilib reset Resource._add_global_resource(self)
def __init__(self, channel): """Create an instance of a digital output. :param channel: the DIO channel for the digital output. 0-9 are on-board, 10-25 are on the MXP """ super().__init__(channel, False) self._pwmGenerator = None self._pwmGenerator_finalizer = None hal.report(hal.UsageReporting.kResourceType_DigitalOutput, channel)
def arcadeDrive( self, xSpeed: float, zRotation: float, squareInputs: bool = True ) -> None: """Arcade drive method for differential drive platform. :param xSpeed: The robot's speed along the X axis `[-1.0..1.0]`. Forward is positive :param zRotation: The robot's zRotation rate around the Z axis `[-1.0..1.0]`. Clockwise is positive :param squareInputs: If set, decreases the sensitivity at low speeds. """ if not self.reported: hal.report( hal.UsageReporting.kResourceType_RobotDrive, 2, hal.UsageReporting.kRobotDrive_ArcadeStandard, ) self.reported = True xSpeed = RobotDriveBase.limit(xSpeed) xSpeed = RobotDriveBase.applyDeadband(xSpeed, self.deadband) zRotation = RobotDriveBase.limit(zRotation) zRotation = RobotDriveBase.applyDeadband(zRotation, self.deadband) if squareInputs: # Square the inputs (while preserving the sign) to increase fine # control while permitting full power. xSpeed = math.copysign(xSpeed * xSpeed, xSpeed) zRotation = math.copysign(zRotation * zRotation, zRotation) maxInput = math.copysign(max(abs(xSpeed), abs(zRotation)), xSpeed) if xSpeed >= 0.0: if zRotation >= 0.0: leftMotorSpeed = maxInput rightMotorSpeed = xSpeed - zRotation else: leftMotorSpeed = xSpeed + zRotation rightMotorSpeed = maxInput else: if zRotation >= 0.0: leftMotorSpeed = xSpeed + zRotation rightMotorSpeed = maxInput else: leftMotorSpeed = maxInput rightMotorSpeed = xSpeed - zRotation leftMotorSpeed = RobotDriveBase.limit(leftMotorSpeed) * self.maxOutput rightMotorSpeed = RobotDriveBase.limit(rightMotorSpeed) * self.maxOutput self.leftMotor.set(leftMotorSpeed) self.rightMotor.set(rightMotorSpeed * self.rightSideInvertMultiplier) self.feed()
def __init__(self, range=Accelerometer.Range.k8G): """Constructor. :param range: The range the accelerometer will measure. Defaults to +/-8g if unspecified. :type range: :class:`.Accelerometer.Range` """ self.setRange(range) hal.report(hal.UsageReporting.kResourceType_Accelerometer, 0, 0, "Built-in accelerometer") LiveWindow.addSensor("BuiltInAccel", 0, self)
def mecanumDrive_Cartesian( self, x: float, y: float, rotation: float, gyroAngle: float ) -> None: """Drive method for Mecanum wheeled robots. A method for driving with Mecanum wheeled robots. There are 4 wheels on the robot, arranged so that the front and back wheels are toed in 45 degrees. When looking at the wheels from the top, the roller axles should form an X across the robot. This is designed to be directly driven by joystick axes. :param x: The speed that the robot should drive in the X direction. [-1.0..1.0] :param y: The speed that the robot should drive in the Y direction. This input is inverted to match the forward == -1.0 that joysticks produce. [-1.0..1.0] :param rotation: The rate of rotation for the robot that is completely independent of the translation. [-1.0..1.0] :param gyroAngle: The current angle reading from the gyro. Use this to implement field-oriented controls. """ if not RobotDrive.kMecanumCartesian_Reported: hal.report( hal.UsageReporting.kResourceType_RobotDrive, self.getNumMotors(), hal.UsageReporting.kRobotDrive_MecanumCartesian, ) RobotDrive.kMecanumCartesian_Reported = True xIn = x yIn = y # Negate y for the joystick. yIn = -yIn # Compensate for gyro angle. xIn, yIn = RobotDrive.rotateVector(xIn, yIn, gyroAngle) wheelSpeeds = [0] * self.kMaxNumberOfMotors wheelSpeeds[self.MotorType.kFrontLeft] = xIn + yIn + rotation wheelSpeeds[self.MotorType.kFrontRight] = -xIn + yIn - rotation wheelSpeeds[self.MotorType.kRearLeft] = -xIn + yIn + rotation wheelSpeeds[self.MotorType.kRearRight] = xIn + yIn - rotation RobotDrive.normalize(wheelSpeeds) self.frontLeftMotor.set(wheelSpeeds[self.MotorType.kFrontLeft] * self.maxOutput) self.frontRightMotor.set( wheelSpeeds[self.MotorType.kFrontRight] * self.maxOutput ) self.rearLeftMotor.set(wheelSpeeds[self.MotorType.kRearLeft] * self.maxOutput) self.rearRightMotor.set(wheelSpeeds[self.MotorType.kRearRight] * self.maxOutput) self.feed()
def launch(cls, vision_py: Optional[str] = None) -> None: """ Launches the CameraServer process in autocapture mode or using a user-specified python script :param vision_py: If specified, this is the relative path to a filename with a function in it Example usage:: wpilib.CameraServer.launch("vision.py:main") .. warning:: You must have robotpy-cscore installed, or this function will fail without returning an error (you will see an error in the console). """ if cls._launched: return cls._launched = True if hal.isSimulation(): logger.info("Would launch CameraServer with vision_py=%s", vision_py) cls._alive = True else: logger.info("Launching CameraServer process") # Launch the cscore launcher in a separate process import sys args = [sys.executable, "-m", "cscore"] # TODO: Get accurate reporting data from the other cscore process. For # now, just differentiate between users with a custom py file and those # who do not. cscore handle values indicate type with bits 24-30 if vision_py: if not vision_py.startswith("/"): vision_py = "/home/lvuser/py/" + vision_py args.append(vision_py) hal.report(hal.UsageReporting.kResourceType_PCVideoServer, 0x51) else: hal.report(hal.UsageReporting.kResourceType_PCVideoServer, 0x52) # We open a pipe to it so that when this process exits, it dies proc = subprocess.Popen( args, close_fds=True, stdin=subprocess.PIPE, cwd="/home/lvuser/py" ) th = threading.Thread(target=cls._monitor_child, args=(proc,)) th.daemon = True th.start()
def __init__(self): self.channelIndex = -1 with self.mutex: for i, v in enumerate(self.filterAllocated): if not v: self.channelIndex = i self.filterAllocated[i] = True hal.report(hal.UsageReporting.kResourceType_DigitalFilter, self.channelIndex, 0) break else: raise ValueError("No more filters available")
def driveCartesian( self, ySpeed: float, xSpeed: float, zRotation: float, gyroAngle: float = 0.0 ) -> None: """Drive method for Mecanum platform. Angles are measured clockwise from the positive X axis. The robot's speed is independent from its angle or rotation rate. :param ySpeed: The robot's speed along the Y axis [-1.0..1.0]. Right is positive. :param xSpeed: The robot's speed along the X axis [-1.0..1.0]. Forward is positive. :param zRotation: The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is positive. :param gyroAngle: The current angle reading from the gyro in degrees around the Z axis. Use this to implement field-oriented controls. """ if not self.reported: hal.report( hal.UsageReporting.kResourceType_RobotDrive, 4, hal.UsageReporting.kRobotDrive2_MecanumCartesian, ) self.reported = True ySpeed = RobotDriveBase.limit(ySpeed) ySpeed = RobotDriveBase.applyDeadband(ySpeed, self.deadband) xSpeed = RobotDriveBase.limit(xSpeed) xSpeed = RobotDriveBase.applyDeadband(xSpeed, self.deadband) # Compensate for gyro angle input = Vector2d(ySpeed, xSpeed) input.rotate(gyroAngle) wheelSpeeds = [ # Front Left input.x + input.y + zRotation, # Rear Left -input.x + input.y + zRotation, # Front Right -input.x + input.y - zRotation, # Rear Right input.x + input.y - zRotation, ] RobotDriveBase.normalize(wheelSpeeds) wheelSpeeds = [speed * self.maxOutput for speed in wheelSpeeds] self.frontLeftMotor.set(wheelSpeeds[0]) self.rearLeftMotor.set(wheelSpeeds[1]) self.frontRightMotor.set(wheelSpeeds[2] * self.rightSideInvertMultiplier) self.rearRightMotor.set(wheelSpeeds[3] * self.rightSideInvertMultiplier) self.feed()
def __init__(self, port): ''' :param port: The port on the driver station that the controller is plugged into. :type port: int ''' warnings.warn('robotpy_ext.control.xbox_controller is deprecated, use wpilib.XboxController instead', category=DeprecationWarning, stacklevel=2) self.ds = wpilib.DriverStation.getInstance() self.port = port hal.report(hal.HALUsageReporting.kResourceType_Joystick, port)
def __init__(self, module: Optional[int] = None) -> None: """Makes a new instance of the compressor using the provided CAN device ID. :param module: The PCM CAN device ID. (0 - 62 inclusive) """ super().__init__() self.table = None if module is None: module = SensorUtil.getDefaultSolenoidModule() self.compressorHandle = hal.initializeCompressor(module) hal.report(hal.UsageReporting.kResourceType_Compressor, module) self.setName("Compressor", module) self.module = module
def __init__(self, period: Optional[float] = None) -> None: if period is None: period = TimedRobot.kDefaultPeriod super().__init__(period) hal.report( hal.UsageReporting.kResourceType_Framework, hal.UsageReporting.kFramework_Timed, ) self._expirationTime = 0 self._notifier = hal.initializeNotifier() Resource._add_global_resource(self)
def startCompetition(self): """ Provide an alternate "main loop" via startCompetition(). Rewritten from IterativeRobot for readability and to initialize scheduler. """ hal.report(hal.HALUsageReporting.kResourceType_Framework, hal.HALUsageReporting.kFramework_Iterative) self.scheduler = Scheduler.getInstance() self.robotInit() # Tell the DS that the robot is ready to be enabled hal.observeUserProgramStarting() # loop forever, calling the appropriate mode-dependent function while True: if self.ds.isDisabled(): hal.observeUserProgramDisabled() self.disabledInit() while self.ds.isDisabled(): self.disabledPeriodic() self.ds.waitForData() elif self.ds.isAutonomous(): hal.observeUserProgramAutonomous() self.autonomousInit() while self.ds.isEnabled() and self.ds.isAutonomous(): self.autonomousPeriodic() self.ds.waitForData() elif self.ds.isTest(): hal.observeUserProgramTest() LiveWindow.setEnabled(True) self.testInit() while self.ds.isEnabled() and self.ds.isTest(): self.testPeriodic() self.ds.waitForData() LiveWindow.setEnabled(False) else: hal.observeUserProgramTeleop() self.teleopInit() # isOperatorControl checks "not autonomous or test", so we need # to check isEnabled as well, since otherwise it will continue # looping while disabled. while self.ds.isEnabled() and self.ds.isOperatorControl(): self.teleopPeriodic() self.ds.waitForData()
def __init__(self, channel): """Create an instance of a Digital Input class. Creates a digital input given a channel. :param channel: the DIO channel for the digital input. 0-9 are on-board, 10-25 are on the MXP :type channel: int """ # Store the channel and generate the handle in the constructor of the parent class # This is different from the Java implementation super().__init__(channel, True) hal.report(hal.UsageReporting.kResourceType_DigitalInput, channel) LiveWindow.addSensor("DigitalInput", channel, self)
def __init__(self, port): """Construct an instance of an XBoxController. The XBoxController index is the USB port on the Driver Station. :param port: The port on the Driver Station that the joystick is plugged into """ super().__init__(port) self.ds = DriverStation.getInstance() self.outputs = 0 self.leftRumble = 0 self.rightRumble = 0 hal.report(hal.UsageReporting.kResourceType_Joystick, port)