Skip to content

Commit 9a15ee3

Browse files
authored
Add expansion hub python code. (#183)
* Improved python tools. Removed _DICT_FULL_MODULE_NAME_TO_MODULE_NAME. Use <module>.__all__ instead. Pass the json_generator_robotpy to the constructor for json_generator_external_samples so it can understand the module exports from robotpy. Renamed SparkMiniComponent to SparkMini. Added expansion_hub.py. * Fixed string concatenations in expansion_hub.py.
1 parent f31ee20 commit 9a15ee3

File tree

14 files changed

+1377
-2343
lines changed

14 files changed

+1377
-2343
lines changed

external_samples/color_range_sensor.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,51 @@
1616
# @fileoverview This is a sample for a color/range sensor
1717
# @author [email protected] (Alan Smith)
1818

19-
from component import Component, PortType, InvalidPortException
2019
from typing import Protocol, Self
20+
from component import Component, PortType, InvalidPortException
2121

2222
class DistanceCallable(Protocol):
2323
def __call__(self, distance : float) -> None:
2424
pass
25+
26+
2527
class ColorCallable(Protocol):
2628
def __call__(self, hue : int, saturation : int, value : int) -> None:
2729
pass
2830

31+
2932
class ColorRangeSensor(Component):
3033
def __init__(self, ports : list[tuple[PortType, int]]):
3134
portType, port = ports[0]
3235
if portType != PortType.I2C_PORT:
3336
raise InvalidPortException
3437
self.port = port
38+
3539
def get_manufacturer(self) -> str:
3640
return "REV Robotics"
41+
3742
def get_name(self) -> str:
3843
return "Color Sensor v3"
44+
3945
def get_part_number(self) -> str:
4046
return "REV-31-1557"
47+
4148
def get_url(self) -> str:
4249
return "https://www.revrobotics.com/rev-31-1557"
50+
4351
def get_version(self) -> tuple[int, int, int]:
4452
return (1, 0, 0)
53+
4554
def stop(self) -> None:
4655
# send stop command to sensor
4756
pass
57+
4858
def reset(self) -> None:
4959
pass
60+
5061
def get_connection_port_type(self) -> list[PortType]:
5162
return [PortType.I2C_PORT]
63+
5264
def periodic(self) -> None:
5365
pass
5466

@@ -62,9 +74,11 @@ def from_i2c_port(cls: type[Self], i2c_port: int) -> Self:
6274
def get_color_rgb(self) -> tuple[int, int, int]:
6375
'''gets the color in rgb (red, green, blue)'''
6476
pass
77+
6578
def get_color_hsv(self) -> tuple[int, int, int]:
6679
'''gets the color in hsv (hue, saturation, value)'''
6780
pass
81+
6882
def get_distance_mm(self) -> float:
6983
'''gets the distance of the object seen'''
7084
pass

external_samples/component.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
class EmptyCallable(Protocol):
2424
def __call__(self) -> None:
2525
pass
26+
27+
2628
class PortType(Enum):
2729
CAN_PORT = 1
2830
SMART_IO_PORT = 2
@@ -31,37 +33,44 @@ class PortType(Enum):
3133
I2C_PORT = 5
3234
USB_PORT = 6
3335

36+
3437
class InvalidPortException(Exception):
3538
pass
3639

40+
3741
# This is an abstract class
3842
class Component(ABC):
3943
@abstractmethod
4044
def __init__(self, ports : list[tuple[PortType, int]]):
4145
pass
42-
# This is the manufacturer of the component
46+
47+
# Returns the manufacturer of the component
4348
@abstractmethod
44-
def get_manufacturer(self) -> str:
45-
pass
46-
# This is the name of the component
49+
def get_manufacturer(self) -> str:
50+
pass
51+
52+
# Returns the name of the component
4753
@abstractmethod
48-
def get_name(self) -> str:
54+
def get_name(self) -> str:
4955
pass
50-
# This is the part number of the component
56+
57+
# Returns the part number of the component
5158
@abstractmethod
52-
def get_part_number(self) -> str:
59+
def get_part_number(self) -> str:
5360
pass
54-
# This is the URL of the component
61+
62+
# Returns the URL of the component
5563
@abstractmethod
56-
def get_url(self) -> str:
64+
def get_url(self) -> str:
5765
pass
58-
# This is the version of the software (returned as a (major, minor, patch) tuple where
66+
67+
# Returns the version of the software (returned as a (major, minor, patch) tuple where
5968
# major, minor and patch are all positive integers
6069
# This MUST follow semantic versioning as described here: https://semver.org/
6170
@abstractmethod
62-
def get_version(self) -> tuple[int, int, int]:
71+
def get_version(self) -> tuple[int, int, int]:
6372
pass
64-
73+
6574
# This stops all movement (if any) for the component
6675
@abstractmethod
6776
def stop(self) -> None:
@@ -73,13 +82,13 @@ def stop(self) -> None:
7382
def reset(self) -> None:
7483
pass
7584

76-
# This returns a list (can be empty, one, or multiple) of the ports this connects to
85+
# Returns a list (can be empty, one, or multiple) of the ports this connects to
7786
# of the PortType enumeration
7887
@abstractmethod
7988
def get_connection_port_type(self) -> list[PortType]:
8089
pass
8190

82-
# This is called periodically when an opmode is running. The component might use this
91+
# This is called periodically when an opmode is running. The component might use this
8392
# to talk to hardware and then call callbacks
8493
@abstractmethod
8594
def periodic(self) -> None:

external_samples/rev_touch_sensor.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,33 @@ def __init__(self, ports : list[tuple[PortType, int]]):
2626
if portType != PortType.SMART_IO_PORT:
2727
raise InvalidPortException
2828
self.port = port
29+
2930
def get_manufacturer(self) -> str:
3031
return "REV Robotics"
32+
3133
def get_name(self) -> str:
3234
return "Touch Sensor"
35+
3336
def get_part_number(self) -> str:
3437
return "REV-31-1425"
38+
3539
def get_url(self) -> str:
3640
return "https://www.revrobotics.com/rev-31-1425/"
41+
3742
def get_version(self) -> tuple[int, int, int]:
3843
return (1, 0, 0)
44+
3945
def stop(self) -> None:
4046
pass
47+
4148
def reset(self) -> None:
4249
self.pressed_callback = None
4350
self.released_callback = None
4451
pass
52+
4553
def get_connection_port_type(self) -> list[PortType]:
4654
return [PortType.SMART_IO_PORT]
55+
4756
def periodic(self) -> None:
4857
old = self.is_pressed
4958
self._read_hardware()

external_samples/servo.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,32 @@ def __init__(self, ports : list[tuple[PortType, int]]):
2525
if portType != PortType.SERVO_PORT:
2626
raise InvalidPortException
2727
self.port = port
28+
2829
def get_manufacturer(self) -> str:
2930
return "REV Robotics"
31+
3032
def get_name(self) -> str:
3133
return "SRS Servo"
34+
3235
def get_part_number(self) -> str:
3336
return "REV-41-1097"
37+
3438
def get_url(self) -> str:
3539
return "https://www.revrobotics.com/rev-41-1097/"
40+
3641
def get_version(self) -> tuple[int, int, int]:
3742
return (1, 0, 0)
43+
3844
def stop(self) -> None:
3945
# De-energize servo port
4046
pass
47+
4148
def reset(self) -> None:
4249
pass
50+
4351
def get_connection_port_type(self) -> list[PortType]:
4452
return [PortType.SERVO_PORT]
53+
4554
def periodic(self) -> None:
4655
pass
4756

@@ -56,6 +65,7 @@ def set_position(self, pos: float) -> None:
5665
'''Set the servo to a position between 0 and 1'''
5766
# sends to the hardware the position of the servo
5867
pass
68+
5969
def set_angle_degrees(self, angle: float) -> None:
6070
'''Set the servo to an angle between 0 and 270'''
6171
self.set_position(angle / 270.0)

external_samples/smart_motor.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,32 @@ def __init__(self, ports : list[tuple[PortType, int]]):
2525
if portType != PortType.SMART_MOTOR_PORT:
2626
raise InvalidPortException
2727
self.port = port
28+
2829
def get_manufacturer(self) -> str:
2930
return "REV Robotics"
31+
3032
def get_name(self) -> str:
3133
return "DC Motor"
34+
3235
def get_part_number(self) -> str:
3336
return "REV-xx-xxxx"
37+
3438
def get_url(self) -> str:
3539
return "https://www.revrobotics.com/rev-xx-xxxx"
40+
3641
def get_version(self) -> tuple[int, int, int]:
3742
return (1, 0, 0)
43+
3844
def stop(self) -> None:
3945
# send stop command to motor
4046
pass
47+
4148
def reset(self) -> None:
4249
pass
50+
4351
def get_connection_port_type(self) -> list[PortType]:
4452
return [PortType.SMART_MOTOR_PORT]
53+
4554
def periodic(self) -> None:
4655
pass
4756

external_samples/spark_mini.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import wpimath
2727
import wpiutil
2828

29-
class SparkMiniComponent(Component):
29+
class SparkMini(Component):
3030
def __init__(self, ports : list[tuple[PortType, int]]):
3131
portType, port = ports[0]
3232
if portType != PortType.SMART_MOTOR_PORT:

python_tools/generate_json.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
# Server python scripts
5454
sys.path.append("../server_python_scripts")
5555
import blocks_base_classes
56+
import expansion_hub # TODO(lizlooney): update this when it is built into robotpy.
5657

5758
# External samples
5859
sys.path.append("../external_samples")
@@ -84,6 +85,7 @@ def main(argv):
8485
pathlib.Path(f'{FLAGS.output_directory}/generated/').mkdir(parents=True, exist_ok=True)
8586

8687
robotpy_modules = [
88+
expansion_hub, # TODO(lizlooney): update this when it is built into robotpy.
8789
ntcore,
8890
wpilib,
8991
wpilib.counter,
@@ -110,16 +112,9 @@ def main(argv):
110112
wpinet,
111113
wpiutil,
112114
]
113-
json_generator = json_util.JsonGenerator(robotpy_modules)
115+
json_generator_robotpy = json_util.JsonGenerator(robotpy_modules)
114116
file_path = f'{FLAGS.output_directory}/generated/robotpy_data.json'
115-
json_generator.writeJsonFile(file_path)
116-
117-
server_python_scripts = [
118-
blocks_base_classes,
119-
]
120-
json_generator = json_util.JsonGenerator(server_python_scripts)
121-
file_path = f'{FLAGS.output_directory}/generated/server_python_scripts.json'
122-
json_generator.writeJsonFile(file_path)
117+
json_generator_robotpy.writeJsonFile(file_path)
123118

124119
external_samples_modules = [
125120
color_range_sensor,
@@ -130,10 +125,18 @@ def main(argv):
130125
spark_mini,
131126
sparkfun_led_stick,
132127
]
133-
json_generator = json_util.JsonGenerator(external_samples_modules)
128+
json_generator_external_samples = json_util.JsonGenerator(
129+
external_samples_modules, [json_generator_robotpy])
134130
file_path = f'{FLAGS.output_directory}/generated/external_samples_data.json'
135-
json_generator.writeJsonFile(file_path)
131+
json_generator_external_samples.writeJsonFile(file_path)
136132

133+
server_python_scripts = [
134+
blocks_base_classes,
135+
]
136+
json_generator_server_python = json_util.JsonGenerator(
137+
server_python_scripts, [json_generator_robotpy])
138+
file_path = f'{FLAGS.output_directory}/generated/server_python_scripts.json'
139+
json_generator_server_python.writeJsonFile(file_path)
137140

138141
if __name__ == '__main__':
139142
app.run(main)

0 commit comments

Comments
 (0)