Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hal/src/main/python/semiwrap/DriverStationTypes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enums:
value_prefix: HAL_kMatchType
HAL_RobotMode:
rename: _RobotMode
value_prefix: HAL_ROBOTMODE
RobotMode:
classes:
HAL_ControlWord:
Expand Down
12 changes: 12 additions & 0 deletions hal/src/main/python/semiwrap/Main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,16 @@ functions:
ignore: true # TODO
HAL_HasMain:
HAL_RunMain:
cpp_code: |
[]() {
{
py::gil_scoped_release gil;
HAL_RunMain();
}

// halsim-gui will set the python error indicator if an exception occurs
if (PyErr_Occurred()) {
throw py::error_already_set();
}
}
HAL_ExitMain:
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ jinja2==3.1.6
protobuf==5.28.3
grpcio-tools==1.68.0
semiwrap==0.2.1
pytest
pytest>=3.9
numpy
opencv-python~=4.6
robotpy-cli~=2027.0.0a1
pytest-reraise
10 changes: 10 additions & 0 deletions requirements_lock.txt
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,12 @@ pygments==2.19.2 \
pytest==8.4.1 \
--hash=sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7 \
--hash=sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c
# via
# -r requirements.txt
# pytest-reraise
pytest-reraise==2.1.2 \
--hash=sha256:5ab59bd0e2028be095289e6dfc9e36cc0b56936465278f3223e81bea0f2d1c70 \
--hash=sha256:c22430d33b2cc18905959d7af28978e371113fcc6ef67b5fec95efcd80b88c16
# via -r requirements.txt
pyyaml==6.0.2 \
--hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \
Expand Down Expand Up @@ -382,6 +388,10 @@ pyyaml==6.0.2 \
--hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \
--hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
# via semiwrap
robotpy-cli==2027.0.1b1 \
--hash=sha256:5f91f6a2e90f6c55800a7a7205180e2454ca961aaf1ef98ce2b63d76aab67505 \
--hash=sha256:f56d8d7444a4aecd4a9c965ef97d4fcf8e951e7ed7a3497f7f8a2635613a5222
# via -r requirements.txt
ruamel-yaml==0.18.14 \
--hash=sha256:710ff198bb53da66718c7db27eec4fbcc9aa6ca7204e4c1df2f282b6fe5eb6b2 \
--hash=sha256:7227b76aaec364df15936730efbf7d72b30c0b79b1d578bbb8e3dcb2d81f52b7
Expand Down
10 changes: 10 additions & 0 deletions requirements_windows_lock.txt
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,12 @@ pygments==2.19.2 \
pytest==8.4.1 \
--hash=sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7 \
--hash=sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c
# via
# -r requirements.txt
# pytest-reraise
pytest-reraise==2.1.2 \
--hash=sha256:5ab59bd0e2028be095289e6dfc9e36cc0b56936465278f3223e81bea0f2d1c70 \
--hash=sha256:c22430d33b2cc18905959d7af28978e371113fcc6ef67b5fec95efcd80b88c16
# via -r requirements.txt
pyyaml==6.0.2 \
--hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \
Expand Down Expand Up @@ -388,6 +394,10 @@ pyyaml==6.0.2 \
--hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \
--hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
# via semiwrap
robotpy-cli==2027.0.1b1 \
--hash=sha256:5f91f6a2e90f6c55800a7a7205180e2454ca961aaf1ef98ce2b63d76aab67505 \
--hash=sha256:f56d8d7444a4aecd4a9c965ef97d4fcf8e951e7ed7a3497f7f8a2635613a5222
# via -r requirements.txt
ruamel-yaml==0.18.14 \
--hash=sha256:710ff198bb53da66718c7db27eec4fbcc9aa6ca7204e4c1df2f282b6fe5eb6b2 \
--hash=sha256:7227b76aaec364df15936730efbf7d72b30c0b79b1d578bbb8e3dcb2d81f52b7
Expand Down
1 change: 1 addition & 0 deletions romiVendordep/robotpy_pybind_build_info.bzl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion romiVendordep/src/main/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ authors = [
license = "BSD-3-Clause"
dependencies = [
"robotpy-native-romi==0.0.0",
"wpilib==0.0.0"
"wpilib==0.0.0",
"robotpy-halsim-ws==0.0.0",
]

[project.urls]
"Source code" = "https://github.com/robotpy/mostrobotpy"

[project.entry-points."robotpy_cli.2027"]
run-romi = "romi.cli:RunRomi"


[tool.hatch.build.hooks.robotpy]
version_file = "romi/version.py"
Expand Down
121 changes: 121 additions & 0 deletions romiVendordep/src/main/python/romi/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import argparse
import importlib.metadata
import os
import sys
import typing

import wpilib


if sys.version_info < (3, 10):

def entry_points(group):
eps = importlib.metadata.entry_points()
return eps.get(group, [])

else:
entry_points = importlib.metadata.entry_points


def _int_env_default(name: str, fallback: int) -> int:
value = os.environ.get(name)
if value is None:
return fallback
try:
return int(value)
except ValueError:
return fallback


class RunRomi:
"""
Runs the robot using the HAL simulator connected to a ROMI
"""

def __init__(self, parser: argparse.ArgumentParser):
parser.add_argument(
"--nogui",
default=False,
action="store_true",
help="Don't use the WPILib simulation gui",
)

sim_group = parser.add_argument_group("Additional simulation extensions")
self.simexts = {}

for entry_point in entry_points(group="robotpy_sim.2027"):
try:
sim_ext_module = entry_point.load()
except ImportError:
print(f"WARNING: Error detected in {entry_point}")
continue

self.simexts[entry_point.name] = sim_ext_module

try:
if entry_point.name == "ws-client":
cmd_help = argparse.SUPPRESS
else:
cmd_help = importlib.metadata.metadata(entry_point.dist.name)[
"summary"
]
except AttributeError:
cmd_help = "Load specified simulation extension"
sim_group.add_argument(
f"--{entry_point.name}",
default=False,
action="store_true",
help=cmd_help,
)

parser.add_argument(
"--host",
default=os.environ.get("HALSIMWS_HOST", "10.0.0.2"),
help="ROMI websocket host (default: HALSIMWS_HOST or 10.0.0.2)",
)
parser.add_argument(
"--port",
type=int,
default=_int_env_default("HALSIMWS_PORT", 3300),
help="ROMI websocket port (default: HALSIMWS_PORT or 3300)",
)

def run(
self,
options: argparse.Namespace,
project_path: "os.PathLike[str]",
robot_class: typing.Type[wpilib.RobotBase],
):
if "ws-client" not in self.simexts:
print(
"ws-client HALSim extension is missing. Reinstall robotpy-halsim-ws to use run-romi",
file=sys.stderr,
)
return False

os.environ["HALSIMWS_HOST"] = options.host
os.environ["HALSIMWS_PORT"] = str(options.port)

options.ws_client = True

if not options.nogui:
try:
import halsim_gui
except ImportError:
print("robotpy-halsim-gui is not installed!", file=sys.stderr)
return False
else:
halsim_gui.loadExtension()

cwd = os.getcwd()

for name, module in self.simexts.items():
if getattr(options, name.replace("-", "_"), False):
try:
module.loadExtension()
except Exception:
print(f"Error loading {name}!", file=sys.stderr)
raise

os.chdir(cwd)
return robot_class.main(robot_class)
20 changes: 16 additions & 4 deletions shared/bazel/rules/robotpy/generate_pybind_build_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,13 +372,24 @@ def target_from_python_dep(python_dep):
base_library = python_dep.replace("robotpy-", "")
return f"//{fixup_root_package_name(base_library)}:{fixup_python_dep_name(python_dep)}"

EXTERNAL_PYPI_DEPS = [
"robotpy-cli",
"pytest-reraise",
"pytest",
]

python_deps = []
has_external_python_deps = False
if "dependencies" in raw_config["project"]:
for d in raw_config["project"]["dependencies"]:
if "robotpy-cli" in d:
continue
pd = target_from_python_dep(d.split("==")[0])
python_deps.append(pd)
for external_dep in EXTERNAL_PYPI_DEPS:
if external_dep in d:
has_external_python_deps = True
python_deps.append(f'requirement("{external_dep}")')
break
else:
pd = target_from_python_dep(d.split("==")[0])
python_deps.append(pd)

env = Environment(loader=BaseLoader)
env.filters["jsonify"] = jsonify
Expand Down Expand Up @@ -410,6 +421,7 @@ def target_from_python_dep(python_dep):
raw_project_config=raw_config["project"],
entry_points=entry_points,
version_file=version_file,
has_external_python_deps=has_external_python_deps,
)
+ "\n"
)
Expand Down
2 changes: 2 additions & 0 deletions shared/bazel/rules/robotpy/generation_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ def fixup_root_package_name(name):
return "romiVendordep"
if name == "pyntcore":
return "ntcore"
if name == "halsim-ws":
return "simulation/halsim_ws_core"
return name


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# THIS FILE IS AUTO GENERATED
{% if publish_casters_targets %}
{% if has_external_python_deps %}
load("@allwpilib_pip_deps//:requirements.bzl", "requirement")
{%- endif %}
{%- if publish_casters_targets %}
load("@rules_cc//cc:cc_library.bzl", "cc_library")
{%- endif %}
{%- if version_file %}
Expand Down Expand Up @@ -211,7 +214,7 @@ def define_pybind_library(name, pkgcfgs = []):
imports = ["{{stripped_include_prefix}}"],
deps = [
{%- for d in python_deps %}
"{{d}}",
{% if "requirement" in d %}{{d}}{% else %}"{{d}}"{% endif %},
{%- endfor %}
],
visibility = ["//visibility:public"],
Expand Down
4 changes: 2 additions & 2 deletions shared/bazel/rules/robotpy/pytest_util.bzl
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
load("@rules_python_pytest//python_pytest:defs.bzl", "py_pytest_test")
load("//shared/bazel/rules/robotpy:compatibility_select.bzl", "robotpy_compatibility_select")

def robotpy_py_test(name, srcs, tags = [], **kwargs):
def robotpy_py_test(name, srcs, tags = [], size = "small", **kwargs):
py_pytest_test(
name = name,
size = "small",
size = size,
srcs = srcs,
target_compatible_with = robotpy_compatibility_select(),
tags = tags + [
Expand Down
32 changes: 32 additions & 0 deletions simulation/halsim_ds_socket/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
load("@allwpilib_pip_deps//:requirements.bzl", "requirement")
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load("@rules_python//python:defs.bzl", "py_library")
load("//shared/bazel/rules:cc_rules.bzl", "wpilib_cc_library", "wpilib_cc_shared_library", "wpilib_cc_static_library")
load("//shared/bazel/rules:packaging.bzl", "package_default_cc_project")
load("//shared/bazel/rules:publishing.bzl", "host_architectures")
load("//shared/bazel/rules/robotpy:pybind_rules.bzl", "copy_native_file")
load("//shared/bazel/rules/robotpy:pytest_util.bzl", "robotpy_py_test")

cc_library(
name = "headers",
Expand Down Expand Up @@ -92,3 +96,31 @@ package_default_cc_project(
maven_artifact_name = "halsim_ds_socket",
maven_group_id = "org.wpilib.halsim",
)

copy_native_file(
name = "halsim_ds_socket",
base_path = "src/main/python/halsim_ds_socket/",
library = "shared/halsim_ds_socket",
)

py_library(
name = "robotpy-halsim-ds-socket",
srcs = glob(["src/main/python/**/*.py"]),
data = [
":halsim_ds_socket.copy_lib",
],
imports = ["src/main/python"],
deps = [
"//hal:robotpy-native-wpihal",
"//wpinet:robotpy-native-wpinet",
],
)

robotpy_py_test(
"python_tests",
srcs = glob(["src/test/python/**/*.py"]),
deps = [
":robotpy-halsim-ds-socket",
requirement("pytest"),
],
)
18 changes: 18 additions & 0 deletions simulation/halsim_ds_socket/src/main/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
robotpy-halsim-ds-socket
==================

Installing this package will allow you to utilize the 2020+ WPILib GUI
DS Socket from a RobotPy program.

Usage
-----

First, install pyfrc. Then run your robot with the 'sim' argument and --ds-socket flag:

# Windows
py -3 -m robotpy sim --ds-socket

# Linux/OSX
python3 -m robotpy sim --ds-socket

WPILib's documentation for using the simulator can be found at http://docs.wpilib.org/en/latest/docs/software/wpilib-tools/robot-simulation/
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .main import loadExtension
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import logging
import os
from os.path import abspath, dirname, join

logger = logging.getLogger("halsim_ds_socket")


def loadExtension():
try:
import hal
except ImportError as e:
# really, should never happen...
raise ImportError("you must install robotpy-hal!") from e

from .version import version

logger.info("WPILib HAL Simulation DS Socket Extension %s", version)

root = join(abspath(dirname(__file__)), "lib")
ext = join(root, os.listdir(root)[0])
retval = hal.loadOneExtension(ext)
if retval != 0:
logger.warn("loading extension may have failed (error=%d)", retval)
Empty file.
Loading
Loading