[copybara] Resync with mostrobotpy (#8662)

This commit is contained in:
PJ Reiniger
2026-03-09 00:38:21 -04:00
committed by GitHub
parent 71cd434699
commit c0f8159540
40 changed files with 181 additions and 79 deletions

View File

@@ -14,9 +14,9 @@ http_archive(
http_archive( http_archive(
name = "pybind11", name = "pybind11",
build_file = "@pybind11_bazel//:pybind11-BUILD.bazel", build_file = "@pybind11_bazel//:pybind11-BUILD.bazel",
integrity = "sha256-wkxQme/TKRS6e0rFedV3IH00zgb8ZsZktnc3HRi9DyU=", integrity = "sha256-LyCgrwuSGBXg4Wnqf+xjkJhpMjWBuJ194VU0aFU/ai0=",
strip_prefix = "pybind11-dfe7e65b4527eeb11036402aac3a394130960bb2", strip_prefix = "pybind11-3.0.2",
urls = ["https://github.com/pybind/pybind11/archive/dfe7e65b4527eeb11036402aac3a394130960bb2.zip"], url = "https://github.com/pybind/pybind11/archive/refs/tags/v3.0.2.tar.gz",
) )
http_archive( http_archive(

View File

@@ -1,7 +1,7 @@
[build-system] [build-system]
build-backend = "hatchling.build" build-backend = "hatchling.build"
requires = [ requires = [
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"hatch-robotpy~=0.2.1", "hatch-robotpy~=0.2.1",
"hatchling", "hatchling",

View File

@@ -75,6 +75,8 @@ class Subsystem(Sendable):
Removes the default command for the subsystem. This will not cancel the default command if it Removes the default command for the subsystem. This will not cancel the default command if it
is currently running. is currently running.
""" """
from .commandscheduler import CommandScheduler
CommandScheduler.getInstance().removeDefaultCommand(self) CommandScheduler.getInstance().removeDefaultCommand(self)
def getDefaultCommand(self) -> Optional[Command]: def getDefaultCommand(self) -> Optional[Command]:

View File

@@ -1,7 +1,7 @@
[build-system] [build-system]
build-backend = "hatchling.build" build-backend = "hatchling.build"
requires = [ requires = [
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"hatchling", "hatchling",
"robotpy-native-datalog==0.0.0", "robotpy-native-datalog==0.0.0",

View File

@@ -1,7 +1,7 @@
[build-system] [build-system]
build-backend = "hatchling.build" build-backend = "hatchling.build"
requires = [ requires = [
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"hatchling", "hatchling",
"pyntcore==0.0.0", "pyntcore==0.0.0",

View File

@@ -241,7 +241,7 @@ inline_code: |2
}); });
cls_SimBoolean cls_SimBoolean
.def_property("value", &SimBoolean::Get, &SimBoolean::Set, release_gil()) .def_property("value", &SimBoolean::Get, &SimBoolean::Set)
.def("__repr__", [](const SimBoolean &self) -> py::str { .def("__repr__", [](const SimBoolean &self) -> py::str {
if (self) { if (self) {
bool value; bool value;
@@ -292,7 +292,7 @@ inline_code: |2
}); });
cls_SimDouble cls_SimDouble
.def_property("value", &SimDouble::Get, &SimDouble::Set, release_gil()) .def_property("value", &SimDouble::Get, &SimDouble::Set)
.def("__repr__", [](const SimDouble &self) -> py::str { .def("__repr__", [](const SimDouble &self) -> py::str {
if (self) { if (self) {
double value; double value;

View File

@@ -1,7 +1,7 @@
[build-system] [build-system]
build-backend = "hatchling.build" build-backend = "hatchling.build"
requires = [ requires = [
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"hatch-robotpy~=0.2.1", "hatch-robotpy~=0.2.1",
"hatchling", "hatchling",

View File

@@ -1,7 +1,7 @@
jinja2==3.1.6 jinja2==3.1.6
protobuf==5.28.3 protobuf==5.28.3
grpcio-tools==1.68.0 grpcio-tools==1.68.0
semiwrap==0.2.6 semiwrap==0.3.0
pytest>=3.9 pytest>=3.9
pytest-reraise pytest-reraise
numpy numpy

View File

@@ -394,9 +394,9 @@ protobuf==5.28.3 \
# via # via
# -r requirements.txt # -r requirements.txt
# grpcio-tools # grpcio-tools
pybind11==3.0.1 \ pybind11==3.0.2 \
--hash=sha256:9c0f40056a016da59bab516efb523089139fcc6f2ba7e4930854c61efb932051 \ --hash=sha256:432f01aeb68e361a3a7fc7575c2c7f497595bf640f747acd909ff238dd766e06 \
--hash=sha256:aa8f0aa6e0a94d3b64adfc38f560f33f15e589be2175e103c0a33c6bce55ee89 --hash=sha256:f8a6500548919cc33bcd220d5f984688326f574fa97f1107f2f4fdb4c6fb019f
# via semiwrap # via semiwrap
pybind11-stubgen==2.5.5 \ pybind11-stubgen==2.5.5 \
--hash=sha256:10824cd2fc5cbbee032b8fb39e6f6c08de232deb309bc66d786a6c6e8a4601bd \ --hash=sha256:10824cd2fc5cbbee032b8fb39e6f6c08de232deb309bc66d786a6c6e8a4601bd \
@@ -566,9 +566,9 @@ ruamel-yaml-clib==0.2.15 \
--hash=sha256:fd4c928ddf6bce586285daa6d90680b9c291cfd045fc40aad34e445d57b1bf51 \ --hash=sha256:fd4c928ddf6bce586285daa6d90680b9c291cfd045fc40aad34e445d57b1bf51 \
--hash=sha256:fe239bdfdae2302e93bd6e8264bd9b71290218fff7084a9db250b55caaccf43f --hash=sha256:fe239bdfdae2302e93bd6e8264bd9b71290218fff7084a9db250b55caaccf43f
# via ruamel-yaml # via ruamel-yaml
semiwrap==0.2.6 \ semiwrap==0.3.0 \
--hash=sha256:cc260ac824af2020f87cc95bc25e41d6486783fe886b43d846b801c034a8a0fb \ --hash=sha256:106a3fc09e31068645bd4c3eab799517bf392ab15a4aa896e947b7a885d79412 \
--hash=sha256:d6ce64193abe8db5743ec27873d65bc53a2a7f35d3c16ce91aa8e9ea21d2d05e --hash=sha256:e215261e387169aacb3c8cf39c711fbcaa59fb9b029d4f1d8d81db9d015c68f3
# via -r requirements.txt # via -r requirements.txt
sphinxify==0.12 \ sphinxify==0.12 \
--hash=sha256:3ec299e78babac7d3457f47bf263411b48e10b9c8add18d7159fa0327cc4a061 \ --hash=sha256:3ec299e78babac7d3457f47bf263411b48e10b9c8add18d7159fa0327cc4a061 \

View File

@@ -398,9 +398,9 @@ protobuf==5.28.3 \
# via # via
# -r requirements.txt # -r requirements.txt
# grpcio-tools # grpcio-tools
pybind11==3.0.1 \ pybind11==3.0.2 \
--hash=sha256:9c0f40056a016da59bab516efb523089139fcc6f2ba7e4930854c61efb932051 \ --hash=sha256:432f01aeb68e361a3a7fc7575c2c7f497595bf640f747acd909ff238dd766e06 \
--hash=sha256:aa8f0aa6e0a94d3b64adfc38f560f33f15e589be2175e103c0a33c6bce55ee89 --hash=sha256:f8a6500548919cc33bcd220d5f984688326f574fa97f1107f2f4fdb4c6fb019f
# via semiwrap # via semiwrap
pybind11-stubgen==2.5.5 \ pybind11-stubgen==2.5.5 \
--hash=sha256:10824cd2fc5cbbee032b8fb39e6f6c08de232deb309bc66d786a6c6e8a4601bd \ --hash=sha256:10824cd2fc5cbbee032b8fb39e6f6c08de232deb309bc66d786a6c6e8a4601bd \
@@ -570,9 +570,9 @@ ruamel-yaml-clib==0.2.15 \
--hash=sha256:fd4c928ddf6bce586285daa6d90680b9c291cfd045fc40aad34e445d57b1bf51 \ --hash=sha256:fd4c928ddf6bce586285daa6d90680b9c291cfd045fc40aad34e445d57b1bf51 \
--hash=sha256:fe239bdfdae2302e93bd6e8264bd9b71290218fff7084a9db250b55caaccf43f --hash=sha256:fe239bdfdae2302e93bd6e8264bd9b71290218fff7084a9db250b55caaccf43f
# via ruamel-yaml # via ruamel-yaml
semiwrap==0.2.6 \ semiwrap==0.3.0 \
--hash=sha256:cc260ac824af2020f87cc95bc25e41d6486783fe886b43d846b801c034a8a0fb \ --hash=sha256:106a3fc09e31068645bd4c3eab799517bf392ab15a4aa896e947b7a885d79412 \
--hash=sha256:d6ce64193abe8db5743ec27873d65bc53a2a7f35d3c16ce91aa8e9ea21d2d05e --hash=sha256:e215261e387169aacb3c8cf39c711fbcaa59fb9b029d4f1d8d81db9d015c68f3
# via -r requirements.txt # via -r requirements.txt
sphinxify==0.12 \ sphinxify==0.12 \
--hash=sha256:3ec299e78babac7d3457f47bf263411b48e10b9c8add18d7159fa0327cc4a061 \ --hash=sha256:3ec299e78babac7d3457f47bf263411b48e10b9c8add18d7159fa0327cc4a061 \

View File

@@ -68,7 +68,9 @@ class Drivetrain:
self.rightEncoder.getDistance(), self.rightEncoder.getDistance(),
) )
def setVelocities(self, velocities: wpimath.DifferentialDriveWheelVelocities) -> None: def setVelocities(
self, velocities: wpimath.DifferentialDriveWheelVelocities
) -> None:
"""Sets the desired wheel velocities. """Sets the desired wheel velocities.
:param velocities: The desired wheel velocities. :param velocities: The desired wheel velocities.

View File

@@ -111,7 +111,9 @@ class Drivetrain:
wpilib.SmartDashboard.putData("Field", self.fieldSim) wpilib.SmartDashboard.putData("Field", self.fieldSim)
wpilib.SmartDashboard.putData("FieldEstimation", self.fieldApproximation) wpilib.SmartDashboard.putData("FieldEstimation", self.fieldApproximation)
def setVelocities(self, velocities: wpimath.DifferentialDriveWheelVelocities) -> None: def setVelocities(
self, velocities: wpimath.DifferentialDriveWheelVelocities
) -> None:
"""Sets the desired wheel velocities. """Sets the desired wheel velocities.
:param velocities: The desired wheel velocities. :param velocities: The desired wheel velocities.

View File

@@ -30,6 +30,8 @@ class ComplexAuto(commands2.SequentialCommandGroup):
ReleaseHatch(hatch), ReleaseHatch(hatch),
# Drive backward the specified distance # Drive backward the specified distance
DriveDistance( DriveDistance(
constants.kAutoBackupDistanceInches, -constants.kAutoDriveVelocity, drive constants.kAutoBackupDistanceInches,
-constants.kAutoDriveVelocity,
drive,
), ),
) )

View File

@@ -114,7 +114,9 @@ class Drivetrain:
"""Method to drive the robot using joystick info.""" """Method to drive the robot using joystick info."""
chassisVelocities = wpimath.ChassisVelocities(xVelocity, yVelocity, rot) chassisVelocities = wpimath.ChassisVelocities(xVelocity, yVelocity, rot)
if fieldRelative: if fieldRelative:
chassisVelocities = chassisVelocities.toRobotRelative(self.imu.getRotation2d()) chassisVelocities = chassisVelocities.toRobotRelative(
self.imu.getRotation2d()
)
self.setVelocities( self.setVelocities(
self.kinematics.toWheelVelocities( self.kinematics.toWheelVelocities(

View File

@@ -144,9 +144,9 @@ class Drivetrain:
self.poseEstimator.getEstimatedPosition().rotation() self.poseEstimator.getEstimatedPosition().rotation()
) )
self.setVelocities( self.setVelocities(
self.kinematics.toWheelVelocities(chassisVelocities.discretize(period)).desaturate( self.kinematics.toWheelVelocities(
self.kMaxVelocity chassisVelocities.discretize(period)
) ).desaturate(self.kMaxVelocity)
) )
def updateOdometry(self) -> None: def updateOdometry(self) -> None:

View File

@@ -88,7 +88,9 @@ class Drivetrain:
self.rightLeader.setInverted(True) self.rightLeader.setInverted(True)
wpilib.SmartDashboard.putData("Field", self.fieldSim) wpilib.SmartDashboard.putData("Field", self.fieldSim)
def setVelocities(self, velocities: wpimath.DifferentialDriveWheelVelocities) -> None: def setVelocities(
self, velocities: wpimath.DifferentialDriveWheelVelocities
) -> None:
"""Sets velocities to the drivetrain motors.""" """Sets velocities to the drivetrain motors."""
leftFeedforward = self.feedforward.calculate(velocities.left) leftFeedforward = self.feedforward.calculate(velocities.left)
rightFeedforward = self.feedforward.calculate(velocities.right) rightFeedforward = self.feedforward.calculate(velocities.right)
@@ -109,7 +111,9 @@ class Drivetrain:
:param rot: the rotation :param rot: the rotation
""" """
self.setVelocities( self.setVelocities(
self.kinematics.toWheelVelocities(wpimath.ChassisVelocities(xVelocity, 0, rot)) self.kinematics.toWheelVelocities(
wpimath.ChassisVelocities(xVelocity, 0, rot)
)
) )
def updateOdometry(self) -> None: def updateOdometry(self) -> None:

View File

@@ -35,7 +35,9 @@ class MyRobot(wpilib.TimedRobot):
self.profile = wpimath.TrapezoidProfile( self.profile = wpimath.TrapezoidProfile(
wpimath.TrapezoidProfile.Constraints( wpimath.TrapezoidProfile.Constraints(
wpimath.units.degreesToRadians(45), wpimath.units.degreesToRadians(45),
wpimath.units.degreesToRadians(90), # Max arm velocity and acceleration. wpimath.units.degreesToRadians(
90
), # Max arm velocity and acceleration.
) )
) )

View File

@@ -39,7 +39,9 @@ class MyRobot(wpilib.TimedRobot):
self.profile = wpimath.TrapezoidProfile( self.profile = wpimath.TrapezoidProfile(
wpimath.TrapezoidProfile.Constraints( wpimath.TrapezoidProfile.Constraints(
wpimath.units.feetToMeters(3.0), wpimath.units.feetToMeters(3.0),
wpimath.units.feetToMeters(6.0), # Max elevator velocity and acceleration. wpimath.units.feetToMeters(
6.0
), # Max elevator velocity and acceleration.
) )
) )

View File

@@ -69,7 +69,9 @@ class Drivetrain:
""" """
robot_velocities = wpimath.ChassisVelocities(xVelocity, yVelocity, rot) robot_velocities = wpimath.ChassisVelocities(xVelocity, yVelocity, rot)
if fieldRelative: if fieldRelative:
robot_velocities = robot_velocities.toRobotRelative(self.imu.getRotation2d()) robot_velocities = robot_velocities.toRobotRelative(
self.imu.getRotation2d()
)
swerveModuleStates = self.kinematics.toSwerveModuleVelocities( swerveModuleStates = self.kinematics.toSwerveModuleVelocities(
wpimath.ChassisVelocities.discretize(robot_velocities, periodSeconds) wpimath.ChassisVelocities.discretize(robot_velocities, periodSeconds)

View File

@@ -82,7 +82,9 @@ class Drivetrain:
chassisVelocities = chassisVelocities.discretize(period) chassisVelocities = chassisVelocities.discretize(period)
states = self.kinematics.toSwerveModuleVelocities(chassisVelocities) states = self.kinematics.toSwerveModuleVelocities(chassisVelocities)
wpimath.SwerveDrive4Kinematics.desaturateWheelVelocities(states, self.kMaxVelocity) wpimath.SwerveDrive4Kinematics.desaturateWheelVelocities(
states, self.kMaxVelocity
)
self.frontLeft.setDesiredVelocity(states[0]) self.frontLeft.setDesiredVelocity(states[0])
self.frontRight.setDesiredVelocity(states[1]) self.frontRight.setDesiredVelocity(states[1])

View File

@@ -77,12 +77,12 @@ class SwerveModule:
# to be continuous. # to be continuous.
self.turningPIDController.enableContinuousInput(-math.pi, math.pi) self.turningPIDController.enableContinuousInput(-math.pi, math.pi)
def getState(self) -> wpimath.SwerveModuleVelocity : def getState(self) -> wpimath.SwerveModuleVelocity:
"""Returns the current state of the module. """Returns the current state of the module.
:returns: The current state of the module. :returns: The current state of the module.
""" """
return wpimath.SwerveModuleVelocity ( return wpimath.SwerveModuleVelocity(
self.driveEncoder.getRate(), self.driveEncoder.getRate(),
wpimath.Rotation2d(self.turningEncoder.getDistance()), wpimath.Rotation2d(self.turningEncoder.getDistance()),
) )

View File

@@ -31,7 +31,9 @@ class Drivetrain(commands2.Subsystem):
self.rightEncoder = wpilib.Encoder(6, 7) self.rightEncoder = wpilib.Encoder(6, 7)
# Set up the differential drive controller # Set up the differential drive controller
self.drive = wpilib.DifferentialDrive(self.leftMotor.setDutyCycle, self.rightMotor.setDutyCycle) self.drive = wpilib.DifferentialDrive(
self.leftMotor.setDutyCycle, self.rightMotor.setDutyCycle
)
# TODO: these don't work # TODO: these don't work
# wpiutil.SendableRegistry.addChild(self.drive, self.leftMotor) # wpiutil.SendableRegistry.addChild(self.drive, self.leftMotor)

View File

@@ -1,7 +1,7 @@
[build-system] [build-system]
build-backend = "hatchling.build" build-backend = "hatchling.build"
requires = [ requires = [
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"hatch-robotpy~=0.2.1", "hatch-robotpy~=0.2.1",
"hatchling", "hatchling",

View File

@@ -1,7 +1,7 @@
[build-system] [build-system]
build-backend = "hatchling.build" build-backend = "hatchling.build"
requires = [ requires = [
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"hatch-robotpy~=0.2.1", "hatch-robotpy~=0.2.1",
"hatchling", "hatchling",

View File

@@ -1,7 +1,15 @@
import ctypes import ctypes
import ctypes.util
import pathlib import pathlib
import sys
import pytest
@pytest.mark.skipif(
sys.platform == "linux" and not ctypes.util.find_library("X11"),
reason="X11 not installed",
)
def test_halsim_gui(): def test_halsim_gui():
# dependencies # dependencies
import wpinet import wpinet

View File

@@ -1,7 +1,7 @@
[build-system] [build-system]
build-backend = "hatchling.build" build-backend = "hatchling.build"
requires = [ requires = [
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"hatch-robotpy~=0.2.1", "hatch-robotpy~=0.2.1",
"hatchling", "hatchling",

View File

@@ -18,6 +18,24 @@ import wpilib
from .pytest_plugin import RobotTestingPlugin from .pytest_plugin import RobotTestingPlugin
class _NullTerminalWriter:
def _highlight(self, source, lexer="python"):
return source
class _NullTerminalReporter:
"""Minimal terminal reporter used in worker processes."""
def __init__(self):
self._tw = _NullTerminalWriter()
def write(self, *args, **kwargs):
pass
def line(self, *args, **kwargs):
pass
def _enable_faulthandler(): def _enable_faulthandler():
# #
# In the event of a segfault, faulthandler will dump the currently # In the event of a segfault, faulthandler will dump the currently
@@ -66,6 +84,15 @@ class WorkerPlugin:
@pytest.hookimpl(wrapper=True) @pytest.hookimpl(wrapper=True)
def pytest_sessionstart(self, session: pytest.Session): def pytest_sessionstart(self, session: pytest.Session):
self.config = session.config self.config = session.config
# When we disable terminalreporter in worker mode we still need a
# minimal reporter so assertion introspection can render diffs.
if self.config.pluginmanager.get_plugin("terminalreporter") is None:
self.config.pluginmanager.unblock("terminalreporter")
self.config.pluginmanager.register(
_NullTerminalReporter(), "terminalreporter"
)
return (yield) return (yield)
@pytest.hookimpl @pytest.hookimpl

View File

@@ -17,9 +17,7 @@ def group_name(request):
AlertSim.resetData() AlertSim.resetData()
def get_active_alerts( def get_active_alerts(group_name: str, level: Alert.Level) -> T.List[str]:
group_name: str, level: Alert.Level
) -> T.List[str]:
return [ return [
a.text a.text
for a in AlertSim.getAll() for a in AlertSim.getAll()
@@ -27,13 +25,14 @@ def get_active_alerts(
] ]
def is_alert_active( def is_alert_active(group_name: str, text: str, level: Alert.Level):
group_name: str, text: str, level: Alert.Level
):
matches = [ matches = [
a a
for a in AlertSim.getAll() for a in AlertSim.getAll()
if a.group == group_name and a.level == level and a.text == text and a.isActive() if a.group == group_name
and a.level == level
and a.text == text
and a.isActive()
] ]
return len(matches) > 0 return len(matches) > 0

View File

@@ -135,7 +135,7 @@ def test_remove_op_mode():
assert options[0].name == "OneArgOpMode" assert options[0].name == "OneArgOpMode"
# @pytest.mark.xfail(reason="wpilib bug") @pytest.mark.xfail(reason="wpilib bug")
def test_none_periodic(): def test_none_periodic():
class MyMockRobot(MockRobot): class MyMockRobot(MockRobot):
def __init__(self): def __init__(self):

View File

@@ -166,6 +166,26 @@ def test_robot_failure_output(robot):
assert robot_pid_one != robot_pid_two assert robot_pid_one != robot_pid_two
def test_isolated_plugin_assertion_rendering(pytester):
_make_robot_module(pytester)
_configure_isolated_plugin(pytester)
pytester.makepyfile(test_isolated="""
def test_robot_assertion_rendering(robot):
assert "x" == "y"
""")
result = pytester.runpytest_subprocess("-vv")
result.assert_outcomes(failed=1)
result.stdout.fnmatch_lines(
[
"*test_isolated.py::test_robot_assertion_rendering FAILED*",
"*assert 'x' == 'y'*",
]
)
assert not any("_pytest/config/__init__.py" in line for line in result.outlines)
def test_isolated_plugin_no_duplicate_verbose_output(pytester): def test_isolated_plugin_no_duplicate_verbose_output(pytester):
_make_robot_module(pytester) _make_robot_module(pytester)
_configure_isolated_plugin(pytester) _configure_isolated_plugin(pytester)

View File

@@ -1,7 +1,7 @@
[build-system] [build-system]
build-backend = "hatchling.build" build-backend = "hatchling.build"
requires = [ requires = [
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"hatch-robotpy~=0.2.1", "hatch-robotpy~=0.2.1",
"hatchling", "hatchling",

View File

@@ -111,4 +111,7 @@ def test_unpack() -> None:
def test_repr() -> None: def test_repr() -> None:
velocities = ChassisVelocities(2.0, 1.0, 0.0) velocities = ChassisVelocities(2.0, 1.0, 0.0)
assert repr(velocities) == "ChassisVelocities(vx=2.000000, vy=1.000000, omega=0.000000)" assert (
repr(velocities)
== "ChassisVelocities(vx=2.000000, vy=1.000000, omega=0.000000)"
)

View File

@@ -40,7 +40,9 @@ def test_straight_line_forward_kinematics(kinematics_test):
wheel_velocities = MecanumDriveWheelVelocities( wheel_velocities = MecanumDriveWheelVelocities(
frontLeft=5, frontRight=5, rearLeft=5, rearRight=5 frontLeft=5, frontRight=5, rearLeft=5, rearRight=5
) )
chassis_velocities = kinematics_test.kinematics.toChassisVelocities(wheel_velocities) chassis_velocities = kinematics_test.kinematics.toChassisVelocities(
wheel_velocities
)
assert chassis_velocities.vx == pytest.approx(5.0, abs=0.1) assert chassis_velocities.vx == pytest.approx(5.0, abs=0.1)
assert chassis_velocities.vy == pytest.approx(0.0, abs=0.1) assert chassis_velocities.vy == pytest.approx(0.0, abs=0.1)
@@ -72,7 +74,9 @@ def test_strafe_forward_kinematics(kinematics_test):
wheel_velocities = MecanumDriveWheelVelocities( wheel_velocities = MecanumDriveWheelVelocities(
frontLeft=-5, frontRight=5, rearLeft=5, rearRight=-5 frontLeft=-5, frontRight=5, rearLeft=5, rearRight=-5
) )
chassis_velocities = kinematics_test.kinematics.toChassisVelocities(wheel_velocities) chassis_velocities = kinematics_test.kinematics.toChassisVelocities(
wheel_velocities
)
assert chassis_velocities.vx == pytest.approx(0.0, abs=0.1) assert chassis_velocities.vx == pytest.approx(0.0, abs=0.1)
assert chassis_velocities.vy == pytest.approx(5.0, abs=0.1) assert chassis_velocities.vy == pytest.approx(5.0, abs=0.1)
@@ -107,7 +111,9 @@ def test_rotation_forward_kinematics(kinematics_test):
rearLeft=-150.79644737, rearLeft=-150.79644737,
rearRight=150.79644737, rearRight=150.79644737,
) )
chassis_velocities = kinematics_test.kinematics.toChassisVelocities(wheel_velocities) chassis_velocities = kinematics_test.kinematics.toChassisVelocities(
wheel_velocities
)
assert chassis_velocities.vx == pytest.approx(0.0, abs=0.1) assert chassis_velocities.vx == pytest.approx(0.0, abs=0.1)
assert chassis_velocities.vy == pytest.approx(0.0, abs=0.1) assert chassis_velocities.vy == pytest.approx(0.0, abs=0.1)
@@ -146,7 +152,9 @@ def test_mixed_rotation_translation_forward_kinematics(kinematics_test):
rearRight=16.26, rearRight=16.26,
) )
chassis_velocities = kinematics_test.kinematics.toChassisVelocities(wheel_velocities) chassis_velocities = kinematics_test.kinematics.toChassisVelocities(
wheel_velocities
)
assert chassis_velocities.vx == pytest.approx(1.41335, abs=0.1) assert chassis_velocities.vx == pytest.approx(1.41335, abs=0.1)
assert chassis_velocities.vy == pytest.approx(2.1221, abs=0.1) assert chassis_velocities.vy == pytest.approx(2.1221, abs=0.1)
@@ -184,7 +192,9 @@ def test_off_center_rotation_forward_kinematics(kinematics_test):
rearLeft=-16.971, rearLeft=-16.971,
rearRight=33.941, rearRight=33.941,
) )
chassis_velocities = kinematics_test.kinematics.toChassisVelocities(wheel_velocities) chassis_velocities = kinematics_test.kinematics.toChassisVelocities(
wheel_velocities
)
assert chassis_velocities.vx == pytest.approx(8.48525, abs=0.1) assert chassis_velocities.vx == pytest.approx(8.48525, abs=0.1)
assert chassis_velocities.vy == pytest.approx(-8.48525, abs=0.1) assert chassis_velocities.vy == pytest.approx(-8.48525, abs=0.1)
@@ -221,7 +231,9 @@ def test_off_center_translation_rotation_forward_kinematics(kinematics_test):
rearLeft=-12.02, rearLeft=-12.02,
rearRight=36.06, rearRight=36.06,
) )
chassis_velocities = kinematics_test.kinematics.toChassisVelocities(wheel_velocities) chassis_velocities = kinematics_test.kinematics.toChassisVelocities(
wheel_velocities
)
assert chassis_velocities.vx == pytest.approx(12.02, abs=0.1) assert chassis_velocities.vx == pytest.approx(12.02, abs=0.1)
assert chassis_velocities.vy == pytest.approx(-7.07, abs=0.1) assert chassis_velocities.vy == pytest.approx(-7.07, abs=0.1)

View File

@@ -164,7 +164,9 @@ def test_turn_in_place_forward_kinematics(kinematics_test):
bl = SwerveModuleVelocity(velocity=106.629, angle=Rotation2d.fromDegrees(-135)) bl = SwerveModuleVelocity(velocity=106.629, angle=Rotation2d.fromDegrees(-135))
br = SwerveModuleVelocity(velocity=106.629, angle=Rotation2d.fromDegrees(-45)) br = SwerveModuleVelocity(velocity=106.629, angle=Rotation2d.fromDegrees(-45))
chassis_velocities = kinematics_test.m_kinematics.toChassisVelocities((fl, fr, bl, br)) chassis_velocities = kinematics_test.m_kinematics.toChassisVelocities(
(fl, fr, bl, br)
)
assert chassis_velocities.vx == pytest.approx(0.0, abs=kEpsilon) assert chassis_velocities.vx == pytest.approx(0.0, abs=kEpsilon)
assert chassis_velocities.vy == pytest.approx(0.0, abs=kEpsilon) assert chassis_velocities.vy == pytest.approx(0.0, abs=kEpsilon)
@@ -209,7 +211,9 @@ def test_off_center_cor_rotation_forward_kinematics(kinematics_test):
bl = SwerveModuleVelocity(velocity=150.796, angle=Rotation2d.fromDegrees(-90)) bl = SwerveModuleVelocity(velocity=150.796, angle=Rotation2d.fromDegrees(-90))
br = SwerveModuleVelocity(velocity=213.258, angle=Rotation2d.fromDegrees(-45)) br = SwerveModuleVelocity(velocity=213.258, angle=Rotation2d.fromDegrees(-45))
chassis_velocities = kinematics_test.m_kinematics.toChassisVelocities((fl, fr, bl, br)) chassis_velocities = kinematics_test.m_kinematics.toChassisVelocities(
(fl, fr, bl, br)
)
assert chassis_velocities.vx == pytest.approx(75.398, abs=kEpsilon) assert chassis_velocities.vx == pytest.approx(75.398, abs=kEpsilon)
assert chassis_velocities.vy == pytest.approx(-75.398, abs=kEpsilon) assert chassis_velocities.vy == pytest.approx(-75.398, abs=kEpsilon)
@@ -254,7 +258,9 @@ def test_off_center_cor_rotation_and_translation_forward_kinematics(kinematics_t
bl = SwerveModuleVelocity(velocity=54.08, angle=Rotation2d.fromDegrees(-109.44)) bl = SwerveModuleVelocity(velocity=54.08, angle=Rotation2d.fromDegrees(-109.44))
br = SwerveModuleVelocity(velocity=54.08, angle=Rotation2d.fromDegrees(-70.56)) br = SwerveModuleVelocity(velocity=54.08, angle=Rotation2d.fromDegrees(-70.56))
chassis_velocities = kinematics_test.m_kinematics.toChassisVelocities((fl, fr, bl, br)) chassis_velocities = kinematics_test.m_kinematics.toChassisVelocities(
(fl, fr, bl, br)
)
assert chassis_velocities.vx == pytest.approx(0.0, abs=kEpsilon) assert chassis_velocities.vx == pytest.approx(0.0, abs=kEpsilon)
assert chassis_velocities.vy == pytest.approx(-33.0, abs=kEpsilon) assert chassis_velocities.vy == pytest.approx(-33.0, abs=kEpsilon)

View File

@@ -1,9 +1,9 @@
[build-system] [build-system]
build-backend = "hatchling.build" build-backend = "hatchling.build"
requires = [ requires = [
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"hatchling", "hatchling",
"robotpy-native-wpinet==0.0.0", "robotpy-native-wpinet==0.0.0",

View File

@@ -36,7 +36,21 @@ includedir = "src/native/wpiutil/include"
libdir = "src/native/wpiutil/lib" libdir = "src/native/wpiutil/lib"
shared_libraries = ["wpiutil"] shared_libraries = ["wpiutil"]
enable_if = "platform_system != 'Windows'" enable_if = "platform_system != 'Windows' and platform_machine != 'aarch64'"
[[tool.hatch.build.hooks.nativelib.pcfile]]
pcfile = "src/native/wpiutil/robotpy-native-wpiutil.pc"
name = "wpiutil"
includedir = "src/native/wpiutil/include"
libdir = "src/native/wpiutil/lib"
shared_libraries = ["wpiutil"]
# abi warnings are obnoxious on arm
extra_cflags = "-Wno-psabi"
enable_if = "platform_system != 'Windows' and platform_machine == 'aarch64'"
[[tool.hatch.build.hooks.nativelib.pcfile]] [[tool.hatch.build.hooks.nativelib.pcfile]]
pcfile = "src/native/wpiutil/robotpy-native-wpiutil.pc" pcfile = "src/native/wpiutil/robotpy-native-wpiutil.pc"

View File

@@ -1,7 +1,7 @@
[build-system] [build-system]
build-backend = "hatchling.build" build-backend = "hatchling.build"
requires = [ requires = [
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"hatch-robotpy~=0.2.1", "hatch-robotpy~=0.2.1",
"hatchling", "hatchling",

View File

@@ -1,15 +1,4 @@
from typing import ClassVar, Protocol from typing import ClassVar, Protocol, TypeGuard
try:
from typing import TypeGuard
except ImportError:
try:
from typing_extensions import TypeGuard
except ImportError:
# Runtime fallback for Python 3.9 without typing_extensions
class TypeGuard:
def __class_getitem__(cls, key):
return bool
class StructSerializable(Protocol): class StructSerializable(Protocol):

View File

@@ -9,9 +9,9 @@ def test_load_array_int():
def test_load_array_annotation(): def test_load_array_annotation():
assert ( assert (
module.load_array_int.__doc__ module.load_array_int.__doc__
== "load_array_int(arg0: Tuple[typing.SupportsInt, typing.SupportsInt, typing.SupportsInt, typing.SupportsInt]) -> Tuple[int, int, int, int]\n" == "load_array_int(arg0: Tuple[typing.SupportsInt | typing.SupportsIndex, typing.SupportsInt | typing.SupportsIndex, typing.SupportsInt | typing.SupportsIndex, typing.SupportsInt | typing.SupportsIndex]) -> Tuple[int, int, int, int]\n"
) )
assert ( assert (
module.load_array_int1.__doc__ module.load_array_int1.__doc__
== "load_array_int1(arg0: Tuple[typing.SupportsInt]) -> Tuple[int]\n" == "load_array_int1(arg0: Tuple[typing.SupportsInt | typing.SupportsIndex]) -> Tuple[int]\n"
) )

View File

@@ -1,7 +1,7 @@
[build-system] [build-system]
build-backend = "hatchling.build" build-backend = "hatchling.build"
requires = [ requires = [
"semiwrap~=0.2.6", "semiwrap~=0.3.0",
"hatch-meson~=0.1.0", "hatch-meson~=0.1.0",
"hatch-robotpy~=0.2.1", "hatch-robotpy~=0.2.1",
"hatchling", "hatchling",