Source code for wpilib.relay

#----------------------------------------------------------------------------
# Copyright (c) FIRST 2008-2012. All Rights Reserved.
# Open Source Software - may be modified and shared by FRC teams. The code
# must be accompanied by the FIRST BSD license file in the root directory of
# the project.
#----------------------------------------------------------------------------

import hal
import weakref

from .livewindow import LiveWindow
from .resource import Resource
from .sensorbase import SensorBase

__all__ = ["Relay"]

def _freeRelay(port):
    hal.setRelayForward(port, False)
    hal.setRelayReverse(port, False)
    hal.freeDIO(port)

[docs]class Relay(SensorBase): """Controls VEX Robotics Spike style relay outputs. Relays are intended to be connected to Spikes or similar relays. The relay channels controls a pair of pins that are either both off, one on, the other on, or both on. This translates into two Spike outputs at 0v, one at 12v and one at 0v, one at 0v and the other at 12v, or two Spike outputs at 12V. This allows off, full forward, or full reverse control of motors without variable speed. It also allows the two channels (forward and reverse) to be used independently for something that does not care about voltage polarity (like a solenoid). .. not_implemented: initRelay """
[docs] class Value: """The state to drive a Relay to.""" #: Off kOff = 0 #: On for relays with defined direction kOn = 1 #: Forward kForward = 2 #: Reverse kReverse = 3
[docs] class Direction: """The Direction(s) that a relay is configured to operate in.""" #: Both directions are valid kBoth = 0 #: Only forward is valid kForward = 1 #: Only reverse is valid kReverse = 2
relayChannels = Resource(SensorBase.kRelayChannels * 2) def __init__(self, channel, direction=None): """Relay constructor given a channel. Initially the relay is set to both lines at 0v. :param channel: The channel number for this relay (0-3) :type channel: int :param direction: The direction that the Relay object will control. If not specified, defaults to allowing both directions. :type direction: :class:`Relay.Direction` """ if direction is None: direction = self.Direction.kBoth self.channel = channel self.direction = direction self._initRelay() LiveWindow.addActuatorChannel("Relay", self.channel, self) self.set(self.Value.kOff) def _initRelay(self): SensorBase.checkRelayChannel(self.channel) try: if (self.direction == self.Direction.kBoth or self.direction == self.Direction.kForward): Relay.relayChannels.allocate(self, self.channel * 2) hal.HALReport(hal.HALUsageReporting.kResourceType_Relay, self.channel) if (self.direction == self.Direction.kBoth or self.direction == self.Direction.kReverse): Relay.relayChannels.allocate(self, self.channel * 2 + 1) hal.HALReport(hal.HALUsageReporting.kResourceType_Relay, self.channel + 128) except IndexError as e: raise IndexError("Relay channel %d is already allocated" % self.channel) from e self._port = hal.initializeDigitalPort(hal.getPort(self.channel)) self._port_finalizer = weakref.finalize(self, _freeRelay, self._port) @property
[docs] def port(self): if not self._port_finalizer.alive: return None return self._port
[docs] def free(self): if (self.direction == self.Direction.kBoth or self.direction == self.Direction.kForward): Relay.relayChannels.free(self.channel*2) if (self.direction == self.Direction.kBoth or self.direction == self.Direction.kReverse): Relay.relayChannels.free(self.channel*2 + 1) self._port_finalizer()
[docs] def set(self, value): """Set the relay state. Valid values depend on which directions of the relay are controlled by the object. When set to kBothDirections, the relay can be set to any of the four states: 0v-0v, 12v-0v, 0v-12v, 12v-12v When set to kForwardOnly or kReverseOnly, you can specify the constant for the direction or you can simply specify kOff and kOn. Using only kOff and kOn is recommended. :param value: The state to set the relay. :type value: :class:`Relay.Value` """ if self.port is None: raise ValueError("operation on freed port") if value == self.Value.kOff: if (self.direction == self.Direction.kBoth or self.direction == self.Direction.kForward): hal.setRelayForward(self.port, False) if (self.direction == self.Direction.kBoth or self.direction == self.Direction.kReverse): hal.setRelayReverse(self.port, False) elif value == self.Value.kOn: if (self.direction == self.Direction.kBoth or self.direction == self.Direction.kForward): hal.setRelayForward(self.port, True) if (self.direction == self.Direction.kBoth or self.direction == self.Direction.kReverse): hal.setRelayReverse(self.port, True) elif value == self.Value.kForward: if self.direction == self.Direction.kReverse: raise ValueError("A relay configured for reverse cannot be set to forward") if (self.direction == self.Direction.kBoth or self.direction == self.Direction.kForward): hal.setRelayForward(self.port, True) if self.direction == self.Direction.kBoth: hal.setRelayReverse(self.port, False) elif value == self.Value.kReverse: if self.direction == self.Direction.kForward: raise ValueError("A relay configured for forward cannot be set to reverse") if self.direction == self.Direction.kBoth: hal.setRelayForward(self.port, False) if (self.direction == self.Direction.kBoth or self.direction == self.Direction.kReverse): hal.setRelayReverse(self.port, True) else: raise ValueError("Invalid value argument '%s'" % value)
[docs] def get(self): """Get the Relay State Gets the current state of the relay. When set to kForwardOnly or kReverseOnly, value is returned as kOn/kOff not kForward/kReverse (per the recommendation in Set) :returns: The current state of the relay :rtype: :class:`Relay.Value` """ if self.port is None: raise ValueError("operation on freed port") if hal.getRelayForward(self.port): if hal.getRelayReverse(self.port): return self.Value.kOn else: if self.direction == self.Direction.kForward: return self.Value.kOn else: return self.Value.kForward else: if hal.getRelayReverse(self.port): if self.direction == self.Direction.kReverse: return self.Value.kOn else: return self.Value.kReverse else: return self.Value.kOff
[docs] def setDirection(self, direction): """Set the Relay Direction. Changes which values the relay can be set to depending on which direction is used. Valid inputs are kBothDirections, kForwardOnly, and kReverseOnly. :param direction: The direction for the relay to operate in :type direction: :class:`Relay.Direction` """ if self.direction == direction: return if direction not in [self.Direction.kBoth, self.Direction.kForward, self.Direction.kReverse]: raise ValueError("Invalid direction argument '%s'" % direction) self.free() self.direction = direction self._initRelay() # Live Window code, only does anything if live window is activated.
def getSmartDashboardType(self): return "Relay" def updateTable(self): table = self.getTable() if table is None: return v = self.get() if v == self.Value.kOn: table.putString("Value", "On") elif v == self.Value.kForward: table.putString("Value", "Forward") elif v == self.Value.kReverse: table.putString("Value", "Reverse") else: table.putString("Value", "Off") def valueChanged(self, itable, key, value, bln): if value == "Off": self.set(self.Value.kOff) elif value == "On": self.set(self.Value.kOn) elif value == "Forward": self.set(self.Value.kForward) elif value == "Reverse": self.set(self.Value.kReverse)