Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
...
  • 16 commits
  • 13 files changed
  • 0 commit comments
  • 3 contributors
@@ -17,20 +17,21 @@ The easiest way to install code on the robot is to use pyfrc.
::
- Windows: py robot.py upload
+ Windows: py robot.py deploy
- Linux/OSX: python3 robot.py upload
+ Linux/OSX: python3 robot.py deploy
-A really useful option is ``--nc``, which will cause the deploy command to show
-your program's console output, by launching a netconsole listener.
+Note that when you run this command like that, you won't get any feedback from the robot whether your code actually worked or not. If you want to see the feedback from your robot, a really useful option is ``--nc``. This will cause the deploy command to show your program's console output, by launching a netconsole listener.
.. code-block:: sh
Windows: py robot.py deploy --nc
Linux/OSX: python3 robot.py deploy --nc
-You can use netconsole and the normal FRC tools to interact with the running robot code.
+You can watch your robot code's output (and see any problems) by using the netconsole program (you can either use NI's tool, or `pynetconsole <https://github.com/robotpy/pynetconsole>`_. You can use netconsole and the normal FRC tools to interact with the running robot code.
+
+If you're having problems deploying code to the robot, check out the troubleshooting section at http://pyfrc.readthedocs.org/en/latest/deploy.html
On the robot (manual)
---------------------
@@ -157,8 +157,7 @@
<file source="examples/MotorControl/robot.py"
destination="src/robot.py"></file>
</files>
- </example>
-<!--
+ </example>
<example>
<name>CAN Talon SRX</name>
<description>Demonstrate running a Talon SRX with the basic throttle mode.</description>
@@ -174,7 +173,7 @@
<file source="examples/CANTalon/robot.py"
destination="src/robot.py"></file>
</files>
- </example>
+ </example>
<example>
<name>CAN Talon SRX PID</name>
@@ -192,7 +191,6 @@
destination="src/robot.py"></file>
</files>
</example>
--->
<tagDescription>
<name>CommandBased Robot</name>
@@ -300,7 +298,7 @@
destination="src/triggers/double_button.py"></file>
</files>
</example>
-<!--
+
<example>
<name>Simple Vision</name>
<description>Demonstrate the use of the CameraServer class to stream from a USB Webcam without processing the images.</description>
@@ -315,7 +313,7 @@
destination="src/robot.py"></file>
</files>
</example>
-
+<!--
<example>
<name>Intermediate Vision</name>
<description>Demonstrate the use of the NIVision class to capture image from a Webcam, process them, and then send them to the dashboard.</description>
@@ -0,0 +1,7 @@
+'''
+ This test module imports tests that come with pyfrc, and can be used
+ to test basic functionality of just about any robot.
+'''
+
+from pyfrc.tests import *
+
@@ -331,6 +331,7 @@ def HALIsSimulation():
setEncoderReverseDirection = _STATUSFUNC("setEncoderReverseDirection", None, ("encoder", Encoder_ptr), ("reverse_direction", C.c_bool))
setEncoderSamplesToAverage = _STATUSFUNC("setEncoderSamplesToAverage", None, ("encoder", Encoder_ptr), ("samples_to_average", C.c_uint32))
getEncoderSamplesToAverage = _STATUSFUNC("getEncoderSamplesToAverage", C.c_uint32, ("encoder", Encoder_ptr))
+setEncoderIndexSource = _STATUSFUNC("setEncoderIndexSource", None, ("encoder", Encoder_ptr), ("pin", C.c_uint32), ("analogTrigger", C.c_bool), ("activeHigh", C.c_bool), ("edgeSensitive", C.c_bool))
getLoopTiming = _STATUSFUNC("getLoopTiming", C.c_uint16)
@@ -9,7 +9,7 @@
git_dir = join(setup_dir, '..', '.git')
base_package = 'hal_impl'
version_file = join(setup_dir, base_package, 'version.py')
-hal_version = 'jenkins-stable-2015.312.beta'
+hal_version = 'jenkins-stable-2015.326'
hal_site = 'http://www.tortall.net/~robotpy/hal'
hal_file = join(setup_dir, base_package, 'libHALAthena_shared.so')
@@ -53,7 +53,7 @@ def _reporthook(count, blocksize, totalsize):
# Generate a new version.py if required
if not exists(version_file) or __version__ != version or __hal_version__ != hal_version:
- with open(join(setup_dir, base_package, 'version.py'), 'w') as fp:
+ with open(version_file, 'w') as fp:
fp.write("# Autogenerated by setup.py\n__version__ = '{0}'\n__hal_version__ = '{1}'".format(version, hal_version))
@@ -163,7 +163,7 @@ def _reset_hal_data(hooks):
'initialized': False,
'voltage': 0.0
- }) for _ in range(2)],
+ }) for _ in range(8)],
# TODO: make this easier to use
'analog_in': [NotifyDict({
@@ -253,7 +253,7 @@ def _reset_hal_data(hooks):
'encoder': [{
'has_source': False,
'initialized': False,
- 'config': [None]*6, # list of pins/modules
+ 'config': {}, # dictionary of pins/modules
'count': 0,
'period': sys.float_info.max,
'max_period': 0,
@@ -970,7 +970,9 @@ def initializeEncoder(port_a_module, port_a_pin, port_a_analog_trigger, port_b_m
enc = hal_data['encoder'][idx]
if enc['initialized'] == False:
enc['initialized'] = True
- enc['config'] = [port_a_module, port_a_pin, port_a_analog_trigger, port_b_module, port_b_pin, port_b_analog_trigger]
+
+ enc['config'] = {"ASource_Module": port_a_module, "ASource_Channel": port_a_pin, "ASource_AnalogTrigger": port_a_analog_trigger,
+ "BSource_Module": port_b_module, "BSource_Channel": port_b_pin, "BSource_AnalogTrigger": port_b_analog_trigger}
enc['reverse_direction'] = reverse_direction
return types.Encoder(idx), idx
@@ -1019,6 +1021,12 @@ def getEncoderSamplesToAverage(encoder, status):
status.value = 0
return hal_data['encoder'][encoder.idx]['samples_to_average']
+def setEncoderIndexSource(encoder, pin, analogTrigger, activeHigh, edgeSensitive, status):
+ status.value = 0
+ index_conf = {"IndexSource_Channel": pin, "IndexSource_Module": 0, "IndexSource_AnalogTrigger": analogTrigger,
+ "IndexActiveHigh": activeHigh, "IndexEdgeSensitive": edgeSensitive}
+ hal_data['encoder'][encoder.idx]['config'].update(index_conf)
+
def getLoopTiming(status):
status.value = 0
return hal_data['pwm_loop_timing']
@@ -324,7 +324,7 @@ def _do_config(self):
#if username != '' and username != self._username:
# config['auth']['username'] = username
#if password != '' and password != self._password:
- # config['auth']['username'] = password
+ # config['auth']['password'] = password
config['auth']['hostname'] = hostname
@@ -16,6 +16,14 @@ def ds(wpimock, halmock):
# Tests
#
+def test_dup(wpilib):
+ '''Don't allow creating a driverStation instance manually'''
+ ds = wpilib.DriverStation.getInstance()
+
+ with pytest.raises(ValueError):
+ _ = wpilib.DriverStation()
+
+
def test_init(wpimock, halmock):
with patch("wpilib.driverstation.threading") as mockthread:
ds = wpimock.DriverStation.getInstance()
@@ -18,10 +18,18 @@ def encoder_data(hal_data):
#port_b_pin
#port_b_analog_trigger False
+def check_config(config, a_mod, a_pin, a_atr, b_mod, b_pin, b_atr):
+ assert config["ASource_Module"] == a_mod
+ assert config["ASource_Channel"] == a_pin
+ assert config["ASource_AnalogTrigger"] == a_atr
+ assert config["BSource_Module"] == b_mod
+ assert config["BSource_Channel"] == b_pin
+ assert config["BSource_AnalogTrigger"] == b_atr
+
def test_channel_channel_init(wpilib, encoder_data):
x = wpilib.Encoder(1, 2)
assert encoder_data["initialized"] == True
- assert encoder_data['config'] == [0, 1, False, 0, 2, False]
+ check_config(encoder_data["config"], 0, 1, False, 0, 2, False)
assert encoder_data['reverse_direction'] == False
x.free()
assert encoder_data["initialized"] == False
@@ -30,7 +38,7 @@ def test_channel_channel_init(wpilib, encoder_data):
def test_channel_channel_reverse_init(wpilib, encoder_data):
x = wpilib.Encoder(1, 2, True)
assert encoder_data["initialized"] == True
- assert encoder_data['config'] == [0, 1, False, 0, 2, False]
+ check_config(encoder_data["config"], 0, 1, False, 0, 2, False)
assert encoder_data['reverse_direction'] == True
x.free()
assert encoder_data["initialized"] == False
@@ -39,7 +47,7 @@ def test_channel_channel_reverse_init(wpilib, encoder_data):
def test_channel_channel_reverse_type_init(wpilib, encoder_data):
x = wpilib.Encoder(1, 2, True, wpilib.Encoder.EncodingType.k4X)
assert encoder_data["initialized"] == True
- assert encoder_data['config'] == [0, 1, False, 0, 2, False]
+ check_config(encoder_data["config"], 0, 1, False, 0, 2, False)
assert encoder_data['reverse_direction'] == True
x.free()
assert encoder_data["initialized"] == False
@@ -48,7 +56,7 @@ def test_channel_channel_reverse_type_init(wpilib, encoder_data):
def test_channel_channel_channel_reverse_init(wpilib, encoder_data):
x = wpilib.Encoder(1, 2, 3, True)
assert encoder_data["initialized"] == True
- assert encoder_data['config'] == [0, 1, False, 0, 2, False]
+ check_config(encoder_data["config"], 0, 1, False, 0, 2, False)
assert encoder_data['reverse_direction'] == True
x.free()
assert encoder_data["initialized"] == False
@@ -57,7 +65,7 @@ def test_channel_channel_channel_reverse_init(wpilib, encoder_data):
def test_channel_channel_channel_init(wpilib, encoder_data):
x = wpilib.Encoder(1, 2, 3)
assert encoder_data["initialized"] == True
- assert encoder_data['config'] == [0, 1, False, 0, 2, False]
+ check_config(encoder_data["config"], 0, 1, False, 0, 2, False)
assert encoder_data['reverse_direction'] == False
x.free()
assert encoder_data["initialized"] == False
@@ -68,7 +76,7 @@ def test_source_source_reverse_init(wpilib, encoder_data):
s2 = wpilib.DigitalInput(2)
x = wpilib.Encoder(s1, s2, True)
assert encoder_data["initialized"] == True
- assert encoder_data['config'] == [0, 1, False, 0, 2, False]
+ check_config(encoder_data["config"], 0, 1, False, 0, 2, False)
assert encoder_data['reverse_direction'] == True
x.free()
s1.free()
@@ -81,7 +89,7 @@ def test_source_source_init(wpilib, encoder_data):
s2 = wpilib.DigitalInput(2)
x = wpilib.Encoder(s1, s2)
assert encoder_data["initialized"] == True
- assert encoder_data['config'] == [0, 1, False, 0, 2, False]
+ check_config(encoder_data["config"], 0, 1, False, 0, 2, False)
assert encoder_data['reverse_direction'] == False
x.free()
s1.free()
@@ -94,7 +102,7 @@ def test_source_source_reverse_type_init(wpilib, encoder_data):
s2 = wpilib.DigitalInput(2)
x = wpilib.Encoder(s1, s2, True, wpilib.Encoder.EncodingType.k4X)
assert encoder_data["initialized"] == True
- assert encoder_data['config'] == [0, 1, False, 0, 2, False]
+ check_config(encoder_data["config"], 0, 1, False, 0, 2, False)
assert encoder_data['reverse_direction'] == True
x.free()
s1.free()
@@ -108,7 +116,7 @@ def test_source_source_source_reverse_init(wpilib, encoder_data):
s3 = wpilib.DigitalInput(3)
x = wpilib.Encoder(s1, s2, s3, True)
assert encoder_data["initialized"] == True
- assert encoder_data['config'] == [0, 1, False, 0, 2, False]
+ check_config(encoder_data["config"], 0, 1, False, 0, 2, False)
assert encoder_data['reverse_direction'] == True
x.free()
s1.free()
@@ -123,7 +131,7 @@ def test_source_source_source_init(wpilib, encoder_data):
s3 = wpilib.DigitalInput(3)
x = wpilib.Encoder(s1, s2, s3)
assert encoder_data["initialized"] == True
- assert encoder_data['config'] == [0, 1, False, 0, 2, False]
+ check_config(encoder_data["config"], 0, 1, False, 0, 2, False)
assert encoder_data['reverse_direction'] == False
x.free()
s1.free()
@@ -40,19 +40,19 @@ def _packINT32(value):
return [x for x in struct.pack("<i", int(value))]
def _unpackPercentage(buffer):
- return struct.unpack("<h", bytes(buffer[:2])) / 32767.0
+ return struct.unpack("<h", bytes(buffer[:2]))[0] / 32767.0
def _unpackFXP8_8(buffer):
- return struct.unpack("<h", bytes(buffer[:2])) / 256.0
+ return struct.unpack("<h", bytes(buffer[:2]))[0] / 256.0
def _unpackFXP16_16(buffer):
- return struct.unpack("<i", bytes(buffer[:4])) / 65536.0
+ return struct.unpack("<i", bytes(buffer[:4]))[0] / 65536.0
def _unpackINT16(buffer):
- return struct.unpack("<h", bytes(buffer[:2]))
+ return struct.unpack("<h", bytes(buffer[:2]))[0]
def _unpackINT32(buffer):
- return struct.unpack("<i", bytes(buffer[:4]))
+ return struct.unpack("<i", bytes(buffer[:4]))[0]
def _FXP8_EQ(a, b):
"""Compare floats for equality as fixed point numbers"""
@@ -65,11 +65,12 @@ def _FXP16_EQ(a, b):
def _sendMessageHelper(messageID, data, period):
if (CANJaguar.kFullMessageIDMask & messageID) in CANJaguar.kTrustedMessages:
# Make sure the data will still fit after adjusting for the token.
- if len(data) > CANJaguar.kMaxMessageDataSize - 2:
+ if data is not None and len(data) > CANJaguar.kMaxMessageDataSize - 2:
raise RuntimeError("CAN message has too much data.")
trustedData = [0, 0] # token placeholder
- trustedData.extend(data)
+ if data is not None:
+ trustedData.extend(data)
frccan.CANSessionMux_sendMessage(messageID, trustedData, period)
else:
frccan.CANSessionMux_sendMessage(messageID, data, period)
@@ -344,16 +345,16 @@ def set(self, outputValue, syncGroup=0):
if self.controlMode == self.ControlMode.PercentVbus:
messageID = _cj.LM_API_VOLT_T_SET
data = _packPercentage(outputValue)
- if self.controlMode == self.ControlMode.Speed:
+ elif self.controlMode == self.ControlMode.Speed:
messageID = _cj.LM_API_SPD_T_SET
data = _packFXP16_16(outputValue)
- if self.controlMode == self.ControlMode.Position:
+ elif self.controlMode == self.ControlMode.Position:
messageID = _cj.LM_API_POS_T_SET
data = _packFXP16_16(outputValue)
- if self.controlMode == self.ControlMode.Current:
+ elif self.controlMode == self.ControlMode.Current:
messageID = _cj.LM_API_ICTRL_T_SET
data = _packFXP8_8(outputValue)
- if self.controlMode == self.ControlMode.Voltage:
+ elif self.controlMode == self.ControlMode.Voltage:
messageID = _cj.LM_API_VCOMP_T_SET
data = _packFXP8_8(outputValue)
else:
@@ -492,7 +493,7 @@ def verify(self):
else:
# It's wrong - set it again
self.setP(self.p)
- except frccan.CANMessageNotFoundException:
+ except frccan.CANMessageNotFound:
# Verification is needed but not available - request it again.
self.requestMessage(message)
@@ -556,7 +557,7 @@ def verify(self):
if not self.encoderCodesPerRevVerified:
try:
- self.getMessage(_cj.LM_API_CFG_ENC_LINES,
+ data = self.getMessage(_cj.LM_API_CFG_ENC_LINES,
_cj.CAN_MSGID_FULL_M)
codes = _unpackINT16(data)
if codes == self.encoderCodesPerRev:
@@ -781,9 +782,9 @@ def setD(self, d):
if self.controlMode == self.ControlMode.Speed:
self.sendMessage(_cj.LM_API_SPD_DC, data)
- if self.controlMode == self.ControlMode.Position:
+ elif self.controlMode == self.ControlMode.Position:
self.sendMessage(_cj.LM_API_POS_DC, data)
- if self.controlMode == self.ControlMode.Current:
+ elif self.controlMode == self.ControlMode.Current:
self.sendMessage(_cj.LM_API_ICTRL_DC, data)
else:
raise ValueError("PID constants only apply in Speed, Position, and Current mode")
@@ -1571,8 +1572,8 @@ def valueChanged(self, itable, key, value, bln):
def startLiveWindowMode(self):
self.set(0) # Stop for safety
- super(LiveWindowSendable, self).startLiveWindowMode()
+ super(CANJaguar, self).startLiveWindowMode()
def stopLiveWindowMode(self):
- super(LiveWindowSendable, self).stopLiveWindowMode()
+ super(CANJaguar, self).stopLiveWindowMode()
self.set(0) # Stop for safety
@@ -45,15 +45,21 @@ def getInstance():
:returns: :class:`DriverStation`
"""
if not hasattr(DriverStation, "instance"):
+ DriverStation.instance = None
DriverStation.instance = DriverStation()
return DriverStation.instance
def __init__(self):
"""DriverStation constructor.
The single DriverStation instance is created statically with the
- instance static member variable.
+ instance static member variable, you should never create a
+ DriverStation instance.
"""
+
+ if not hasattr(DriverStation, 'instance') or DriverStation.instance is not None:
+ raise ValueError("Do not create DriverStation instances, use DriverStation.getInstance() instead")
+
self.mutex = threading.RLock()
self.dataSem = threading.Condition(self.mutex)
Oops, something went wrong.

No commit comments for this range