mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-29 02:21:44 +00:00
Compare commits
54 Commits
v2027.0.0-
...
v2026.2.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ca35e5678 | ||
|
|
613bd88548 | ||
|
|
e311722637 | ||
|
|
ae43b8b6dd | ||
|
|
5ae8ee06dd | ||
|
|
d9eba4bb22 | ||
|
|
9cd933fa14 | ||
|
|
77dfad97c6 | ||
|
|
7ac0612397 | ||
|
|
2c5529d714 | ||
|
|
7cd3790c7c | ||
|
|
664484306c | ||
|
|
0a37317467 | ||
|
|
6b225bb1f1 | ||
|
|
3d92547d62 | ||
|
|
c89401250f | ||
|
|
8be7720a68 | ||
|
|
21b5389bbe | ||
|
|
9e1258440b | ||
|
|
812a1b8e1a | ||
|
|
18249badc0 | ||
|
|
b82d204525 | ||
|
|
ccb3266753 | ||
|
|
71a788e20b | ||
|
|
f395954d3c | ||
|
|
ab3af00d07 | ||
|
|
1b2f051b4b | ||
|
|
3dc334c1ee | ||
|
|
baa6379267 | ||
|
|
0d1dd84e86 | ||
|
|
a61866912b | ||
|
|
57c40a3dfc | ||
|
|
6f86f533e5 | ||
|
|
ded6790bcd | ||
|
|
769ce5e9fa | ||
|
|
f6b4ad575b | ||
|
|
7cd0ef5bd9 | ||
|
|
bd7a88a6d0 | ||
|
|
95cb38e6df | ||
|
|
b8d6bc2eb1 | ||
|
|
688535298b | ||
|
|
02252b58d7 | ||
|
|
e207ca4880 | ||
|
|
f4db88da9a | ||
|
|
e45aadc851 | ||
|
|
fea6883d98 | ||
|
|
b7fe5ef833 | ||
|
|
cd237e57d4 | ||
|
|
8b99ad82c3 | ||
|
|
58ba536351 | ||
|
|
4aef52a117 | ||
|
|
a6a4912a80 | ||
|
|
873e960e93 | ||
|
|
4f133c6aa1 |
30
.bazelrc
30
.bazelrc
@@ -1,24 +1,18 @@
|
||||
try-import %workspace%/bazel_auth.rc
|
||||
try-import %workspace%/user.bazelrc
|
||||
|
||||
common --noenable_bzlmod --enable_workspace
|
||||
# Resolves to --config=linux on Linux, --config=macos on Mac, --windows on windows
|
||||
common --enable_platform_specific_config
|
||||
common --noenable_bzlmod
|
||||
|
||||
# Make bazel 8 work for us.
|
||||
common --enable_workspace
|
||||
build --experimental_cc_static_library
|
||||
build --experimental_cc_shared_library
|
||||
|
||||
build --java_language_version=21
|
||||
build --java_runtime_version=remotejdk_21
|
||||
build --tool_java_language_version=21
|
||||
build --tool_java_runtime_version=remotejdk_21
|
||||
build --java_language_version=17
|
||||
build --java_runtime_version=roboriojdk_17
|
||||
build --tool_java_language_version=17
|
||||
build --tool_java_runtime_version=remotejdk_17
|
||||
|
||||
test --test_output=errors
|
||||
test --test_verbose_timeout_warnings
|
||||
|
||||
import %workspace%/shared/bazel/compiler_flags/sanitizers.rc
|
||||
import %workspace%/shared/bazel/compiler_flags/base_linux_flags.rc
|
||||
import %workspace%/shared/bazel/compiler_flags/linux_flags.rc
|
||||
import %workspace%/shared/bazel/compiler_flags/osx_flags.rc
|
||||
import %workspace%/shared/bazel/compiler_flags/roborio_flags.rc
|
||||
@@ -35,7 +29,6 @@ build:build_java --test_tag_filters=allwpilib-build-java --build_tag_filters=all
|
||||
build:build_cpp --test_tag_filters=+allwpilib-build-cpp --build_tag_filters=+allwpilib-build-cpp
|
||||
build:no_example --test_tag_filters=-wpi-example --build_tag_filters=-wpi-example
|
||||
test:no_example --test_tag_filters=-wpi-example --build_tag_filters=-wpi-example
|
||||
common:skip_robotpy --test_tag_filters=-robotpy --build_tag_filters=-robotpy
|
||||
|
||||
# Build Buddy Cache Setup
|
||||
build:build_buddy --bes_results_url=https://app.buildbuddy.io/invocation/
|
||||
@@ -62,14 +55,3 @@ build:ci --config=build_buddy
|
||||
build:ci --remote_download_minimal
|
||||
|
||||
build --build_metadata=REPO_URL=https://github.com/wpilibsuite/allwpilib.git
|
||||
|
||||
common --define="WPILIB_VERSION=2025.424242.3.1-unknown"
|
||||
|
||||
# List of artifact types to build in CI.
|
||||
# Anything else gets skipped to speed up CI.
|
||||
common:ci --repo_env="WPI_PUBLISH_CLASSIFIER_FILTER=headers,sources,linuxsystemcore,linuxsystemcoredebug,linuxsystemcorestatic,linuxsystemcorestaticdebug,linuxx86-64,linuxx86-64debug,linuxx86-64static,linuxx86-64staticdebug,osxuniversal,osxuniversaldebug,osxuniversalstatic,osxuniversalstaticdebug,windowsarm64,windowsarm64debug,windowsarm64static,windowsarm64staticdebug,windowsx86-64,windowsx86-64debug,windowsx86-64static,windowsx86-64staticdebug"
|
||||
|
||||
# The 2 configurations for windows are very slow to build each time.
|
||||
# Instead, skip the cross transition for ARM on x86, and the reverse on x86.
|
||||
common:ci_windows_x86 --repo_env="WPI_PUBLISH_CLASSIFIER_FILTER=headers,sources,linuxsystemcore,linuxsystemcoredebug,linuxsystemcorestatic,linuxsystemcorestaticdebug,linuxx86-64,linuxx86-64debug,linuxx86-64static,linuxx86-64staticdebug,osxuniversal,osxuniversaldebug,osxuniversalstatic,osxuniversalstaticdebug,windowsx86-64,windowsx86-64debug,windowsx86-64static,windowsx86-64staticdebug"
|
||||
common:ci_windows_arm --repo_env="WPI_PUBLISH_CLASSIFIER_FILTER=headers,sources,linuxsystemcore,linuxsystemcoredebug,linuxsystemcorestatic,linuxsystemcorestaticdebug,linuxx86-64,linuxx86-64debug,linuxx86-64static,linuxx86-64staticdebug,osxuniversal,osxuniversaldebug,osxuniversalstatic,osxuniversalstaticdebug,windowsarm64,windowsarm64debug,windowsarm64static,windowsarm64staticdebug"
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.4.1
|
||||
7.3.1
|
||||
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -28,5 +28,3 @@
|
||||
|
||||
# Generated files
|
||||
*/src/generated/** linguist-generated
|
||||
*/robotpy_native_build_info.bzl linguist-generated
|
||||
*/robotpy_pybind_build_info.bzl linguist-generated
|
||||
|
||||
8
.github/actions/pregen/action.yml
vendored
8
.github/actions/pregen/action.yml
vendored
@@ -18,6 +18,9 @@ runs:
|
||||
wget https://github.com/HebiRobotics/QuickBuffers/releases/download/1.3.3/protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
chmod +x protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
shell: bash
|
||||
- name: Regenerate hal
|
||||
run: ./hal/generate_usage_reporting.py
|
||||
shell: bash
|
||||
|
||||
- name: Regenerate ntcore
|
||||
run: ./ntcore/generate_topics.py
|
||||
@@ -53,11 +56,6 @@ runs:
|
||||
./wpimath/generate_quickbuf.py --quickbuf_plugin protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
shell: bash
|
||||
|
||||
- name: Regenerate Commands v3
|
||||
run: |
|
||||
./commandsv3/generate_files.py --quickbuf_plugin protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
shell: bash
|
||||
|
||||
- name: Regenerate wpiunits
|
||||
run: ./wpiunits/generate_units.py
|
||||
shell: bash
|
||||
|
||||
11
.github/actions/setup-build-buddy/action.yml
vendored
11
.github/actions/setup-build-buddy/action.yml
vendored
@@ -8,7 +8,6 @@ inputs:
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# Sets up build buddy when no secret is found for the API key. This is most likely because this is triggered from an action from a fork instead of the main allwpilib repo.
|
||||
- name: Setup without key
|
||||
env:
|
||||
API_KEY: ${{ inputs.token }}
|
||||
@@ -18,16 +17,6 @@ runs:
|
||||
echo "No API key secret detected, will setup readonly cache"
|
||||
echo "build:ci --config=build_buddy_readonly" > bazel_auth.rc
|
||||
|
||||
# Set up the readonly key only if this build is for a pull request. Push builds happen in the forks repository,
|
||||
# so the user should set their own buildbuddy api keys up there. Only enabling it for PR's should reduce heavy
|
||||
# and more random load on the cache.
|
||||
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
||||
echo "Assuming this is a pull request from a fork. Setting up the readonly api key"
|
||||
echo "build:ci --remote_header=x-buildbuddy-api-key=QIOV65PTW1tVal3AJbe7" >> bazel_auth.rc
|
||||
else
|
||||
echo "Not setting up readonly key for trigger ${{ github.event_name }} since this is not a pull request, it is most likely a forks push. See the buildbuddy setup guide in README-Bazel.md to set up caching on your fork"
|
||||
fi
|
||||
|
||||
- name: Set with key
|
||||
env:
|
||||
API_KEY: ${{ inputs.token }}
|
||||
|
||||
3
.github/labeler.yml
vendored
3
.github/labeler.yml
vendored
@@ -33,6 +33,9 @@
|
||||
'component: sysid':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: sysid/**
|
||||
'component: teamnumbersetter':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: roborioteamnumbersetter/**
|
||||
'component: wpilibc':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: wpilibc/**
|
||||
|
||||
31
.github/workflows/bazel.yml
vendored
31
.github/workflows/bazel.yml
vendored
@@ -12,8 +12,8 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { name: "Windows (native)", os: windows-2022, action: "test", config: "--config=ci_windows_x86", }
|
||||
- { name: "Windows (arm)", os: windows-2022, action: "build", config: "--config=windows_arm --config=ci_windows_arm", }
|
||||
- { name: "Windows (native)", os: windows-2022, action: "test", config: "--config=windows", }
|
||||
- { name: "Windows (arm)", os: windows-2022, action: "build", config: "--config=windows_arm", }
|
||||
|
||||
name: "Build ${{ matrix.name }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -22,8 +22,8 @@ jobs:
|
||||
with: { fetch-depth: 0 }
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
distribution: 'zulu'
|
||||
java-version: 17
|
||||
architecture: x64
|
||||
|
||||
- id: Setup_build_buddy
|
||||
@@ -32,28 +32,23 @@ jobs:
|
||||
token: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
|
||||
- name: bazel ${{ matrix.action }}
|
||||
run: bazel ${{ matrix.action }} -k ... --config=ci ${{ matrix.config }} --verbose_failures
|
||||
run: bazel --output_user_root=C:\\bazelroot ${{ matrix.action }} -k ... --config=ci ${{ matrix.config }} --verbose_failures
|
||||
shell: bash
|
||||
|
||||
build-mac:
|
||||
name: "Mac"
|
||||
runs-on: macos-14
|
||||
runs-on: macOS-15
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with: { fetch-depth: 0 }
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
|
||||
- id: Setup_build_buddy
|
||||
uses: ./.github/actions/setup-build-buddy
|
||||
with:
|
||||
token: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
|
||||
- name: bazel test (release)
|
||||
run: bazel test -k ... --config=ci -c opt --nojava_header_compilation --verbose_failures
|
||||
run: bazel test -k ... --config=ci -c opt --config=macos --nojava_header_compilation --verbose_failures
|
||||
shell: bash
|
||||
|
||||
build-linux:
|
||||
@@ -61,10 +56,10 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { name: "Linux", os: ubuntu-24.04, container: "wpilib/systemcore-cross-ubuntu:2027-24.04", action: "test", config: "", }
|
||||
- { name: "Linux (native)", os: ubuntu-22.04, action: "test", config: "--config=linux", }
|
||||
- { name: "Linux (roborio)", os: ubuntu-22.04, action: "build", config: "--config=roborio", }
|
||||
name: "${{ matrix.name }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
container: ${{ matrix.container }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with: { fetch-depth: 0 }
|
||||
@@ -75,18 +70,12 @@ jobs:
|
||||
with:
|
||||
token: ${{ secrets.BUILDBUDDY_API_KEY }}
|
||||
|
||||
- uses: bazel-contrib/setup-bazel@0.15.0
|
||||
with:
|
||||
bazelisk-cache: true
|
||||
repository-cache: true
|
||||
bazelisk-version: 1.x
|
||||
|
||||
- name: bazel ${{ matrix.action }} (release)
|
||||
run: bazel ${{ matrix.action }} ... --config=ci -c opt ${{ matrix.config }} -k --verbose_failures
|
||||
|
||||
buildifier:
|
||||
name: "buildifier"
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Set up Go 1.15.x
|
||||
uses: actions/setup-go@v5
|
||||
|
||||
10
.github/workflows/cmake-android.yml
vendored
10
.github/workflows/cmake-android.yml
vendored
@@ -16,10 +16,10 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-24.04
|
||||
- os: ubuntu-22.04
|
||||
name: Android Arm64
|
||||
abi: arm64-v8a
|
||||
- os: ubuntu-24.04
|
||||
- os: ubuntu-22.04
|
||||
name: Android X64
|
||||
abi: "x86_64"
|
||||
|
||||
@@ -30,13 +30,13 @@ jobs:
|
||||
- uses: nttld/setup-ndk@v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: r27c
|
||||
ndk-version: r27d
|
||||
add-to-path: false
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
java-version: 17
|
||||
|
||||
- name: Install sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.9
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
run: sudo apt-get update && sudo apt-get install -y ninja-build
|
||||
|
||||
- name: configure
|
||||
run: cmake --preset with-sccache -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_WPILIB=OFF -DWITH_GUI=OFF -DWITH_CSCORE=OFF -DWITH_TESTS=OFF -DWITH_SIMULATION_MODULES=OFF -DWITH_JAVA=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_TOOLCHAIN_FILE=${{ steps.setup-ndk.outputs.ndk-path }}/build/cmake/android.toolchain.cmake -DANDROID_ABI="${{ matrix.abi }}" -DANDROID_PLATFORM=android-24
|
||||
run: cmake --preset with-sccache -DCMAKE_BUILD_TYPE=RelWithDebInfo -DWITH_WPILIB=OFF -DWITH_GUI=OFF -DWITH_CSCORE=OFF -DWITH_TESTS=OFF -DWITH_SIMULATION_MODULES=OFF -DWITH_PROTOBUF=OFF -DWITH_JAVA=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_TOOLCHAIN_FILE=${{ steps.setup-ndk.outputs.ndk-path }}/build/cmake/android.toolchain.cmake -DANDROID_ABI="${{ matrix.abi }}" -DANDROID_PLATFORM=android-24
|
||||
env:
|
||||
SCCACHE_WEBDAV_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
SCCACHE_WEBDAV_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
|
||||
13
.github/workflows/cmake.yml
vendored
13
.github/workflows/cmake.yml
vendored
@@ -16,13 +16,14 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-24.04
|
||||
- os: ubuntu-22.04
|
||||
name: Linux
|
||||
container: wpilib/systemcore-cross-ubuntu:2027-24.04
|
||||
container: wpilib/roborio-cross-ubuntu:2025-22.04
|
||||
flags: "--preset with-java-and-sccache -DCMAKE_BUILD_TYPE=Release -DWITH_EXAMPLES=ON"
|
||||
- os: macOS-14
|
||||
- os: macOS-15
|
||||
name: macOS
|
||||
container: ""
|
||||
env: ""
|
||||
flags: "--preset with-sccache -DCMAKE_BUILD_TYPE=Release -DWITH_EXAMPLES=ON"
|
||||
- os: windows-2022
|
||||
name: Windows
|
||||
@@ -35,11 +36,11 @@ jobs:
|
||||
steps:
|
||||
- name: Install dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv-java ninja-build
|
||||
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv4.5-java libprotobuf-dev protobuf-compiler ninja-build
|
||||
|
||||
- name: Install dependencies (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install opencv ninja
|
||||
run: brew install opencv protobuf@29 ninja
|
||||
|
||||
- uses: ilammy/msvc-dev-cmd@v1.13.0
|
||||
if: runner.os == 'Windows'
|
||||
@@ -58,7 +59,7 @@ jobs:
|
||||
uses: lukka/run-vcpkg@v11.5
|
||||
with:
|
||||
vcpkgDirectory: ${{ runner.workspace }}/vcpkg
|
||||
vcpkgGitCommitId: 37c3e63a1306562f7f59c4c3c8892ddd50fdf992 # HEAD on 2024-02-24
|
||||
vcpkgGitCommitId: 74e6536215718009aae747d86d84b78376bf9e09 # HEAD on 2025-10-17
|
||||
|
||||
- name: configure
|
||||
run: cmake ${{ matrix.flags }}
|
||||
|
||||
110
.github/workflows/gradle.yml
vendored
110
.github/workflows/gradle.yml
vendored
@@ -19,20 +19,20 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- container: wpilib/systemcore-cross-ubuntu:2027-24.04
|
||||
artifact-name: SystemCore
|
||||
build-options: "-Ponlylinuxsystemcore"
|
||||
- container: wpilib/raspbian-cross-ubuntu:2027-bookworm-24.04
|
||||
- container: wpilib/roborio-cross-ubuntu:2025-22.04
|
||||
artifact-name: Athena
|
||||
build-options: "-Ponlylinuxathena"
|
||||
- container: wpilib/raspbian-cross-ubuntu:bookworm-22.04
|
||||
artifact-name: Arm32
|
||||
build-options: "-Ponlylinuxarm32"
|
||||
- container: wpilib/aarch64-cross-ubuntu:2027-bookworm-24.04
|
||||
- container: wpilib/aarch64-cross-ubuntu:bookworm-22.04
|
||||
artifact-name: Arm64
|
||||
build-options: "-Ponlylinuxarm64"
|
||||
- container: wpilib/systemcore-cross-ubuntu:2027-24.04
|
||||
- container: wpilib/ubuntu-base:22.04
|
||||
artifact-name: Linux
|
||||
build-options: "-Ponlylinuxx86-64"
|
||||
name: "Build - ${{ matrix.artifact-name }}"
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
steps:
|
||||
- name: Free Disk Space
|
||||
@@ -50,13 +50,13 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Set release environment variable
|
||||
run: echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v2027')
|
||||
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')
|
||||
- name: Build with Gradle
|
||||
uses: addnab/docker-run-action@v3
|
||||
uses: wpilibsuite/docker-run-action@v4
|
||||
with:
|
||||
image: ${{ matrix.container }}
|
||||
options: -v ${{ github.workspace }}:/work -w /work -e ARTIFACTORY_PUBLISH_USERNAME -e ARTIFACTORY_PUBLISH_PASSWORD -e GITHUB_REF -e CI
|
||||
run: df . && rm -f semicolon_delimited_script && echo $GITHUB_REF && ./gradlew build --build-cache -PbuildServer -PskipJavaFormat ${{ matrix.build-options }} ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
run: df . && echo $GITHUB_REF && ./gradlew build --build-cache -PbuildServer -PskipJavaFormat ${{ matrix.build-options }} ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
env:
|
||||
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
@@ -98,11 +98,17 @@ jobs:
|
||||
build-options: "-PciReleaseOnly -Pbuildwinarm64 -Ponlywindowsarm64"
|
||||
task: "copyAllOutputs"
|
||||
outputs: "build/allOutputs"
|
||||
- os: macOS-14
|
||||
- os: macOS-15
|
||||
artifact-name: macOS
|
||||
architecture: aarch64
|
||||
task: "build"
|
||||
outputs: "build/allOutputs"
|
||||
- os: windows-2022
|
||||
artifact-name: Win32FFI
|
||||
architecture: x86
|
||||
task: ":ntcoreffi:build"
|
||||
build-options: "-Pntcoreffibuild \"-Dorg.gradle.jvmargs=-Xmx1096m\""
|
||||
outputs: "ntcoreffi/build/outputs"
|
||||
- os: windows-2022
|
||||
artifact-name: Win64FFI
|
||||
architecture: x64
|
||||
@@ -119,7 +125,7 @@ jobs:
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
java-version: 17
|
||||
architecture: ${{ matrix.architecture }}
|
||||
- name: Import Developer ID Certificate
|
||||
uses: wpilibsuite/import-signing-certificate@v2
|
||||
@@ -129,22 +135,25 @@ jobs:
|
||||
keychain-password: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
|
||||
if: |
|
||||
matrix.artifact-name == 'macOS' && (github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027')))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027'))))
|
||||
- name: Set Keychain Lock Timeout
|
||||
run: security set-keychain-settings -lut 21600
|
||||
if: |
|
||||
matrix.artifact-name == 'macOS' && (github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027')))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027'))))
|
||||
- name: Set release environment variable
|
||||
run: echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
if: startsWith(github.ref, 'refs/tags/v2027')
|
||||
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')
|
||||
- name: Set Java Heap Size
|
||||
run: sed -i 's/-Xmx2g/-Xmx1g/g' gradle.properties
|
||||
if: matrix.artifact-name == 'Win32'
|
||||
- name: Check disk free space (Windows)
|
||||
run: wmic logicaldisk get caption, freespace
|
||||
if: matrix.os == 'windows-2022'
|
||||
- name: Check disk free space pre-cleanup (macOS)
|
||||
run: df -h .
|
||||
if: matrix.os == 'macOS-14'
|
||||
if: matrix.os == 'macOS-15'
|
||||
- name: Cleanup disk space
|
||||
# CodeQL: 5G
|
||||
# go: 748M
|
||||
@@ -153,10 +162,10 @@ jobs:
|
||||
rm -rf /Users/runner/hostedtoolcache/CodeQL
|
||||
rm -rf /Users/runner/hostedtoolcache/go
|
||||
rm -rf /Users/runner/Library/Android
|
||||
if: matrix.os == 'macOS-14'
|
||||
if: matrix.os == 'macOS-15'
|
||||
- name: Check disk free space post-cleanup (macOS)
|
||||
run: df -h .
|
||||
if: matrix.os == 'macOS-14'
|
||||
if: matrix.os == 'macOS-15'
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew ${{ matrix.task }} --build-cache -PbuildServer -PskipJavaFormat ${{ matrix.build-options }} ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
env:
|
||||
@@ -166,13 +175,13 @@ jobs:
|
||||
run: ./gradlew copyAllOutputs --build-cache -PbuildServer -PskipJavaFormat -PdeveloperID=${{ secrets.APPLE_DEVELOPER_ID }} ${{ matrix.build-options }} ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
if: |
|
||||
matrix.artifact-name == 'macOS' && (github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027')))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027'))))
|
||||
- name: Check disk free space (Windows)
|
||||
run: wmic logicaldisk get caption, freespace
|
||||
if: matrix.os == 'windows-2022'
|
||||
- name: Check disk free space (macOS)
|
||||
run: df -h .
|
||||
if: matrix.os == 'macOS-14'
|
||||
if: matrix.os == 'macOS-15'
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
@@ -180,7 +189,7 @@ jobs:
|
||||
|
||||
build-documentation:
|
||||
name: "Build - Documentation"
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -189,10 +198,10 @@ jobs:
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
java-version: 17
|
||||
- name: Set release environment variable
|
||||
run: echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v2027')
|
||||
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew docs:zipDocs --build-cache -PbuildServer -PdocWarningsAsErrors ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
env:
|
||||
@@ -206,7 +215,7 @@ jobs:
|
||||
publish:
|
||||
name: "Documentation - Publish"
|
||||
runs-on: ubuntu-22.04
|
||||
if: github.repository == 'wpilibsuite/allwpilib' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
if: github.repository == 'wpilibsuite/allwpilib' && (github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
needs: [build-documentation]
|
||||
concurrency: ci-docs-publish
|
||||
steps:
|
||||
@@ -240,11 +249,6 @@ jobs:
|
||||
echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
echo "BRANCH=release" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, 'alpha') && !contains(github.ref, 'beta') && !contains(github.ref, '2027')
|
||||
- name: Set environment variables (2027)
|
||||
run: |
|
||||
echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
echo "BRANCH=2027" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v') && contains(github.ref, '2027')
|
||||
- name: Install SSH Client 🔑
|
||||
uses: webfactory/ssh-agent@v0.9.0
|
||||
with:
|
||||
@@ -273,12 +277,12 @@ jobs:
|
||||
combine:
|
||||
name: Combine
|
||||
needs: [build-docker, build-host, build-documentation]
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Free Disk Space
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
tool-cache: false
|
||||
@@ -291,48 +295,48 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
with:
|
||||
repository: wpilibsuite/build-tools
|
||||
- uses: actions/download-artifact@v4
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
with:
|
||||
path: combiner/products/build/allOutputs
|
||||
- name: Flatten Artifacts
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
run: rsync -a --delete combiner/products/build/allOutputs/*/* combiner/products/build/allOutputs/
|
||||
- name: Check version number exists
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
run: |
|
||||
cat combiner/products/build/allOutputs/version.txt
|
||||
test -s combiner/products/build/allOutputs/version.txt
|
||||
- uses: actions/setup-java@v4
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
- name: Combine (2027)
|
||||
java-version: 17
|
||||
- name: Combine (Main)
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
github.ref == 'refs/heads/2027'
|
||||
run: cd combiner && ./gradlew publish -Pallwpilib -Pbuild2027
|
||||
github.ref == 'refs/heads/main'
|
||||
run: cd combiner && ./gradlew publish -Pallwpilib
|
||||
env:
|
||||
RUN_AZURE_ARTIFACTORY_RELEASE: "TRUE"
|
||||
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
- name: Combine (2027 Release)
|
||||
- name: Combine (Release)
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
startsWith(github.ref, 'refs/tags/v2027')
|
||||
run: cd combiner && ./gradlew publish -Pallwpilib -PreleaseRepoPublish -Pbuild2027
|
||||
startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')
|
||||
run: cd combiner && ./gradlew publish -Pallwpilib -PreleaseRepoPublish
|
||||
env:
|
||||
RUN_AZURE_ARTIFACTORY_RELEASE: "TRUE"
|
||||
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
@@ -340,7 +344,25 @@ jobs:
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
(github.ref == 'refs/heads/2027' || startsWith(github.ref, 'refs/tags/v2027'))
|
||||
(github.ref == 'refs/heads/main' || (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')))
|
||||
with:
|
||||
name: Maven
|
||||
path: ~/releases
|
||||
|
||||
dispatch:
|
||||
name: dispatch
|
||||
needs: [combine]
|
||||
strategy:
|
||||
matrix:
|
||||
repo: ['SmartDashboard', 'PathWeaver', 'Shuffleboard', 'RobotBuilder']
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: peter-evans/repository-dispatch@v3
|
||||
if: |
|
||||
github.repository == 'wpilibsuite/allwpilib' &&
|
||||
startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '2027')
|
||||
with:
|
||||
token: ${{ secrets.TOOL_REPO_ACCESS_TOKEN }}
|
||||
repository: wpilibsuite/${{ matrix.repo }}
|
||||
event-type: tag
|
||||
client-payload: '{"package_name": "allwpilib", "package_version": "${{ github.ref_name }}"}'
|
||||
|
||||
14
.github/workflows/lint-format.yml
vendored
14
.github/workflows/lint-format.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
|
||||
wpiformat:
|
||||
name: "wpiformat"
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
- name: Install wpiformat
|
||||
run: |
|
||||
python -m venv ${{ runner.temp }}/wpiformat
|
||||
${{ runner.temp }}/wpiformat/bin/pip3 install wpiformat==2025.34
|
||||
${{ runner.temp }}/wpiformat/bin/pip3 install wpiformat==2025.36
|
||||
- name: Run
|
||||
run: ${{ runner.temp }}/wpiformat/bin/wpiformat
|
||||
- name: Check output
|
||||
@@ -59,9 +59,9 @@ jobs:
|
||||
|
||||
tidy:
|
||||
name: "clang-tidy"
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
container: wpilib/ubuntu-base:24.04
|
||||
container: wpilib/ubuntu-base:22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
- name: Install wpiformat
|
||||
run: |
|
||||
python -m venv ${{ runner.temp }}/wpiformat
|
||||
${{ runner.temp }}/wpiformat/bin/pip3 install wpiformat==2025.34
|
||||
${{ runner.temp }}/wpiformat/bin/pip3 install wpiformat==2025.36
|
||||
- name: Create compile_commands.json
|
||||
run: |
|
||||
./gradlew generateCompileCommands -Ptoolchain-optional-roboRio
|
||||
@@ -92,9 +92,9 @@ jobs:
|
||||
run: ${{ runner.temp }}/wpiformat/bin/wpiformat -no-format -tidy-changed -compile-commands=build/TargetedCompileCommands/linuxx86-64debug -vv
|
||||
javaformat:
|
||||
name: "Java format"
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
container: wpilib/systemcore-cross-ubuntu:2027-24.04
|
||||
container: wpilib/ubuntu-base:22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
2
.github/workflows/pregenerate.yml
vendored
2
.github/workflows/pregenerate.yml
vendored
@@ -13,7 +13,7 @@ concurrency:
|
||||
jobs:
|
||||
update:
|
||||
name: "Update"
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
4
.github/workflows/sanitizers.yml
vendored
4
.github/workflows/sanitizers.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
container: wpilib/roborio-cross-ubuntu:2025-24.04
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv-java clang-18 ninja-build
|
||||
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv-java clang-17 libprotobuf-dev protobuf-compiler ninja-build
|
||||
|
||||
- name: Install sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.9
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: configure
|
||||
run: mkdir build && cd build && cmake -G Ninja -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang-18 -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++-18 -DWITH_JAVA=OFF ${{ matrix.cmake-flags }} ..
|
||||
run: mkdir build && cd build && cmake -G Ninja -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang-17 -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++-17 -DWITH_JAVA=OFF ${{ matrix.cmake-flags }} ..
|
||||
env:
|
||||
SCCACHE_WEBDAV_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
SCCACHE_WEBDAV_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
|
||||
39
.github/workflows/sentinel-build.yml
vendored
39
.github/workflows/sentinel-build.yml
vendored
@@ -23,20 +23,20 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- container: wpilib/systemcore-cross-ubuntu:2027-24.04
|
||||
artifact-name: SystemCore
|
||||
build-options: "-Ponlylinuxsystemcore"
|
||||
- container: wpilib/raspbian-cross-ubuntu:2027-bookworm-24.04
|
||||
- container: wpilib/roborio-cross-ubuntu:2025-22.04
|
||||
artifact-name: Athena
|
||||
build-options: "-Ponlylinuxathena"
|
||||
- container: wpilib/raspbian-cross-ubuntu:bookworm-22.04
|
||||
artifact-name: Arm32
|
||||
build-options: "-Ponlylinuxarm32"
|
||||
- container: wpilib/aarch64-cross-ubuntu:2027-bookworm-24.04
|
||||
- container: wpilib/aarch64-cross-ubuntu:bookworm-22.04
|
||||
artifact-name: Arm64
|
||||
build-options: "-Ponlylinuxarm64"
|
||||
- container: wpilib/systemcore-cross-ubuntu:2027-24.04
|
||||
- container: wpilib/ubuntu-base:22.04
|
||||
artifact-name: Linux
|
||||
build-options: "-Ponlylinuxx86-64"
|
||||
name: "Build - ${{ matrix.artifact-name }}"
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [validation]
|
||||
steps:
|
||||
- name: Free Disk Space
|
||||
@@ -53,11 +53,11 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Build with Gradle
|
||||
uses: addnab/docker-run-action@v3
|
||||
uses: wpilibsuite/docker-run-action@v4
|
||||
with:
|
||||
image: ${{ matrix.container }}
|
||||
options: -v ${{ github.workspace }}:/work -w /work -e GITHUB_REF -e CI
|
||||
run: df . && rm -f semicolon_delimited_script && echo $GITHUB_REF && ./gradlew build -PbuildServer -PskipJavaFormat ${{ matrix.build-options }}
|
||||
run: df . && echo $GITHUB_REF && ./gradlew build -PbuildServer -PskipJavaFormat ${{ matrix.build-options }}
|
||||
- name: Check free disk space
|
||||
run: df .
|
||||
- uses: actions/upload-artifact@v4
|
||||
@@ -97,11 +97,17 @@ jobs:
|
||||
build-options: "-PciReleaseOnly -Pbuildwinarm64 -Ponlywindowsarm64"
|
||||
task: "copyAllOutputs"
|
||||
outputs: "build/allOutputs"
|
||||
- os: macOS-14
|
||||
- os: macOS-15
|
||||
artifact-name: macOS
|
||||
architecture: aarch64
|
||||
task: "build"
|
||||
outputs: "build/allOutputs"
|
||||
- os: windows-2022
|
||||
artifact-name: Win32FFI
|
||||
architecture: x86
|
||||
task: ":ntcoreffi:build"
|
||||
build-options: "-Pntcoreffibuild \"-Dorg.gradle.jvmargs=-Xmx1096m\""
|
||||
outputs: "ntcoreffi/build/outputs"
|
||||
- os: windows-2022
|
||||
artifact-name: Win64FFI
|
||||
architecture: x64
|
||||
@@ -118,7 +124,7 @@ jobs:
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
java-version: 17
|
||||
architecture: ${{ matrix.architecture }}
|
||||
- name: Import Developer ID Certificate
|
||||
uses: wpilibsuite/import-signing-certificate@v2
|
||||
@@ -132,12 +138,15 @@ jobs:
|
||||
run: security set-keychain-settings -lut 21600
|
||||
if: |
|
||||
matrix.artifact-name == 'macOS' && (github.repository_owner == 'wpilibsuite' && github.ref == 'refs/heads/main')
|
||||
- name: Set Java Heap Size
|
||||
run: sed -i 's/-Xmx2g/-Xmx1g/g' gradle.properties
|
||||
if: matrix.artifact-name == 'Win32'
|
||||
- name: Check disk free space (Windows)
|
||||
run: wmic logicaldisk get caption, freespace
|
||||
if: matrix.os == 'windows-2022'
|
||||
- name: Check disk free space pre-cleanup (macOS)
|
||||
run: df -h .
|
||||
if: matrix.os == 'macOS-14'
|
||||
if: matrix.os == 'macOS-15'
|
||||
- name: Cleanup disk space
|
||||
# CodeQL: 5G
|
||||
# go: 748M
|
||||
@@ -146,10 +155,10 @@ jobs:
|
||||
rm -rf /Users/runner/hostedtoolcache/CodeQL
|
||||
rm -rf /Users/runner/hostedtoolcache/go
|
||||
rm -rf /Users/runner/Library/Android
|
||||
if: matrix.os == 'macOS-14'
|
||||
if: matrix.os == 'macOS-15'
|
||||
- name: Check disk free space post-cleanup (macOS)
|
||||
run: df -h .
|
||||
if: matrix.os == 'macOS-14'
|
||||
if: matrix.os == 'macOS-15'
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew ${{ matrix.task }} -PbuildServer -PskipJavaFormat ${{ matrix.build-options }}
|
||||
- name: Sign Libraries with Developer ID
|
||||
@@ -161,7 +170,7 @@ jobs:
|
||||
if: matrix.os == 'windows-2022'
|
||||
- name: Check disk free space (macOS)
|
||||
run: df -h .
|
||||
if: matrix.os == 'macOS-14'
|
||||
if: matrix.os == 'macOS-15'
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
|
||||
196
.github/workflows/tools.yml
vendored
Normal file
196
.github/workflows/tools.yml
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
name: Tools
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
YEAR: 2026
|
||||
|
||||
jobs:
|
||||
build-artifacts:
|
||||
name: "Build - WPILib"
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
DISPLAY: ':10'
|
||||
steps:
|
||||
- name: Free Disk Space
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
tool-cache: false
|
||||
android: true
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: false
|
||||
docker-images: false
|
||||
swap-storage: false
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: gradle/actions/wrapper-validation@v4
|
||||
- name: Build WPILib with Gradle
|
||||
uses: wpilibsuite/docker-run-action@v4
|
||||
with:
|
||||
image: wpilib/roborio-cross-ubuntu:2025-22.04
|
||||
options: -v ${{ github.workspace }}:/work -w /work -e GITHUB_REF -e CI -e DISPLAY
|
||||
run: df . && ./gradlew :wpilibc:publish :wpilibj:publish :wpilibNewCommands:publish :hal:publish :cameraserver:publish :ntcore:publish :cscore:publish :wpimath:publish :wpinet:publish :wpiutil:publish :apriltag:publish :wpiunits:publish :simulation:halsim_gui:publish :simulation:halsim_ds_socket:publish :simulation:halsim_ws_server:publish :simulation:halsim_ws_client:publish :simulation:halsim_xrp:publish :fieldImages:publish :romiVendordep:publish :xrpVendordep:publish :epilogue-processor:publish :epilogue-runtime:publish :thirdparty:googletest:publish -x test -x Javadoc -x doxygen --build-cache && cp -r /root/releases/maven/development /work
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MavenArtifacts
|
||||
path: |
|
||||
development
|
||||
retention-days: 1
|
||||
|
||||
Robotbuilder:
|
||||
name: "Build - RobotBuilder"
|
||||
needs: [build-artifacts]
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
DISPLAY: ':10'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: wpilibsuite/robotbuilder
|
||||
fetch-depth: 0
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: MavenArtifacts
|
||||
- name: Patch RobotBuilder to use local development
|
||||
run: cd src/main/resources/export && echo "wpi.maven.useLocal = false" >> java/build.gradle && echo "wpi.maven.useFrcMavenLocalDevelopment = true" >> java/build.gradle && echo "wpi.versions.wpilibVersion = '$YEAR.424242.+'" >> java/build.gradle && echo "wpi.versions.wpimathVersion = '$YEAR.424242.+'" >> java/build.gradle && echo "wpi.maven.useLocal = false" >> cpp/build.gradle && echo "wpi.maven.useFrcMavenLocalDevelopment = true" >> cpp/build.gradle && echo "wpi.versions.wpilibVersion = '$YEAR.424242.+'" >> cpp/build.gradle && echo "wpi.versions.wpimathVersion = '$YEAR.424242.+'" >> cpp/build.gradle
|
||||
- name: Install and run xvfb
|
||||
run: sudo apt-get update && sudo apt-get install -y xvfb && Xvfb $DISPLAY &
|
||||
- name: Move artifacts
|
||||
run: mkdir -p ~/releases/maven/development && cp -r edu ~/releases/maven/development
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
- name: Build RobotBuilder with Gradle
|
||||
run: ./gradlew build test --tests 'robotbuilder.exporters.*' -x htmlSanityCheck -PbuildServer -PreleaseMode ; cat build/test-results/test/TEST-robotbuilder.exporters.*.xml ;
|
||||
- name: Summarize RobotBuilder Test Results
|
||||
uses: EnricoMi/publish-unit-test-result-action@v2
|
||||
if: always()
|
||||
with:
|
||||
files: |
|
||||
build/test-results/test/TEST*.xml
|
||||
check_run: false
|
||||
comment_mode: off
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: RobotBuilderTestResults
|
||||
path: |
|
||||
build/reports/
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: RobotBuilder Build
|
||||
path: |
|
||||
build/libs/
|
||||
retention-days: 7
|
||||
|
||||
Shuffleboard:
|
||||
name: "Build - Shuffleboard"
|
||||
needs: [build-artifacts]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: wpilibsuite/shuffleboard
|
||||
fetch-depth: 0
|
||||
- name: Patch Shuffleboard to use local development
|
||||
run: sed -i "s/wpilibTools.deps.wpilibVersion.*/wpilibTools.deps.wpilibVersion = \'$YEAR\.424242\.+\'/" app/app.gradle && sed -i "s/wpilibTools.deps.wpilibVersion.*/wpilibTools.deps.wpilibVersion = \'$YEAR\.424242\.+\'/" plugins/cameraserver/cameraserver.gradle && sed -i "s/wpilibTools.deps.wpilibVersion.*/wpilibTools.deps.wpilibVersion = \'$YEAR\.424242\.+\'/" plugins/networktables/networktables.gradle
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: MavenArtifacts
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
- name: Move artifacts
|
||||
run: mkdir -p ~/releases/maven/development && cp -r edu ~/releases/maven/development
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -y libgtk2.0-0
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build -x Javadoc
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Shuffleboard Build
|
||||
path: |
|
||||
build/allOutputs/
|
||||
retention-days: 7
|
||||
|
||||
PathWeaver:
|
||||
name: "Build - PathWeaver"
|
||||
needs: [build-artifacts]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: wpilibsuite/PathWeaver
|
||||
fetch-depth: 0
|
||||
- name: Patch PathWeaver to use local development
|
||||
run: sed -i "s/wpilibTools.deps.wpilibVersion.*/wpilibTools.deps.wpilibVersion = \'$YEAR\.424242\.+\'/" dependencies.gradle
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: MavenArtifacts
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
- name: Move artifacts
|
||||
run: mkdir -p ~/releases/maven/development && cp -r edu ~/releases/maven/development
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: PathWeaver Build
|
||||
path: |
|
||||
build/allOutputs/
|
||||
retention-days: 7
|
||||
|
||||
# Robotpy:
|
||||
# name: "Build - Robotpy"
|
||||
# needs: [build-artifacts]
|
||||
# runs-on: ubuntu-22.04
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# with:
|
||||
# repository: robotpy/mostrobotpy
|
||||
# fetch-depth: 0
|
||||
# - uses: actions/download-artifact@v4
|
||||
# with:
|
||||
# name: MavenArtifacts
|
||||
# - name: Move artifacts
|
||||
# run: mkdir -p ~/releases/maven/development && cp -r edu ~/releases/maven/development
|
||||
#
|
||||
# - uses: actions/setup-python@v5
|
||||
# with:
|
||||
# python-version: 3.13
|
||||
#
|
||||
# - name: Install sccache
|
||||
# uses: mozilla-actions/sccache-action@v0.0.9
|
||||
#
|
||||
# - name: Install deps
|
||||
# shell: bash
|
||||
# run: |
|
||||
# python -m pip --disable-pip-version-check install -r rdev_requirements.txt
|
||||
#
|
||||
# - name: Install numpy (needed for stubgen but broken in raspbian CI)
|
||||
# shell: bash
|
||||
# run: |
|
||||
# python -m pip --disable-pip-version-check install numpy
|
||||
# - name: Patch RobotPy rdev to use local development
|
||||
# run: git config user.name github-actions && git config user.email github-actions@github.com && set -- ~/releases/maven/development/edu/wpi/first/wpiutil/wpiutil-cpp/*/ ; wpilibversion=$(basename $1) && echo $wpilibversion && sed --regexp-extended -i 's@(wpilib_bin_url =).*@\1 \"file:\/\/'"$HOME"'\/releases\/maven\/development"@' rdev.toml && sed --regexp-extended -i 's/(wpilib_bin_version =).*/\1 \"'"$wpilibversion"'\"/' rdev.toml && ./rdev.sh update-pyproject --commit
|
||||
# - name: Build + test wheels
|
||||
# shell: bash
|
||||
# run: |
|
||||
# ./rdev.sh ci run
|
||||
# env:
|
||||
# RPYBUILD_STRIP_LIBPYTHON: "1"
|
||||
# RPYBUILD_CC_LAUNCHER: sccache
|
||||
# SCCACHE_WEBDAV_ENDPOINT: "https://frcmaven.wpi.edu/artifactory/wpilib-generic-cache-cmake-local"
|
||||
# SCCACHE_WEBDAV_KEY_PREFIX: "sccache-robotpy"
|
||||
# SCCACHE_WEBDAV_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
# SCCACHE_WEBDAV_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
14
.github/workflows/upstream-utils.yml
vendored
14
.github/workflows/upstream-utils.yml
vendored
@@ -13,7 +13,7 @@ concurrency:
|
||||
jobs:
|
||||
update:
|
||||
name: "Update"
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -120,6 +120,12 @@ jobs:
|
||||
./mpack.py clone
|
||||
./mpack.py copy-src
|
||||
./mpack.py format-patch
|
||||
- name: Run protobuf.py
|
||||
run: |
|
||||
cd upstream_utils
|
||||
./protobuf.py clone
|
||||
./protobuf.py copy-src
|
||||
./protobuf.py format-patch
|
||||
- name: Run sleipnir.py
|
||||
run: |
|
||||
cd upstream_utils
|
||||
@@ -132,12 +138,6 @@ jobs:
|
||||
./stb.py clone
|
||||
./stb.py copy-src
|
||||
./stb.py format-patch
|
||||
- name: Run upb.py
|
||||
run: |
|
||||
cd upstream_utils
|
||||
./upb.py clone
|
||||
./upb.py copy-src
|
||||
./upb.py format-patch
|
||||
- name: Add untracked files to index so they count as changes
|
||||
run: git add -A
|
||||
- name: Check output
|
||||
|
||||
10
.styleguide
10
.styleguide
@@ -14,7 +14,6 @@ modifiableFileExclude {
|
||||
thirdparty/
|
||||
\.patch$
|
||||
gradlew
|
||||
BUILD.bazel
|
||||
}
|
||||
|
||||
generatedFileExclude {
|
||||
@@ -23,13 +22,6 @@ generatedFileExclude {
|
||||
fieldImages/src/main/native/resources/
|
||||
apriltag/src/test/resources/
|
||||
wpilibc/src/generated/
|
||||
|
||||
apriltag/src/main/python/
|
||||
apriltag/src/test/python/
|
||||
wpilibc/src/main/python/
|
||||
wpilibc/src/test/python/
|
||||
xrpVendordep/src/main/python/
|
||||
xrpVendordep/src/test/python/
|
||||
}
|
||||
|
||||
repoRootNameOverride {
|
||||
@@ -42,6 +34,7 @@ includeOtherLibs {
|
||||
^cscore
|
||||
^fmt/
|
||||
^glass/
|
||||
^google/
|
||||
^gtest/
|
||||
^hal/
|
||||
^imgui
|
||||
@@ -53,7 +46,6 @@ includeOtherLibs {
|
||||
^support/
|
||||
^units/
|
||||
^unsupported/
|
||||
^upb/
|
||||
^vision/
|
||||
^wpi/
|
||||
^wpigui
|
||||
|
||||
128
BUILD.bazel
128
BUILD.bazel
@@ -1,128 +0,0 @@
|
||||
load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files")
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_files")
|
||||
load("@rules_python//python:pip.bzl", "compile_pip_requirements")
|
||||
load("//shared/bazel/rules:publishing.bzl", "publish_all")
|
||||
|
||||
exports_files([
|
||||
"LICENSE.md",
|
||||
"ThirdPartyNotices.txt",
|
||||
])
|
||||
|
||||
pkg_files(
|
||||
name = "license_pkg_files",
|
||||
srcs = [
|
||||
"LICENSE.md",
|
||||
"ThirdPartyNotices.txt",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# bazel build //:requirements.lock
|
||||
compile_pip_requirements(
|
||||
name = "requirements",
|
||||
extra_args = ["--allow-unsafe"],
|
||||
requirements_in = "requirements.txt",
|
||||
requirements_txt = "requirements_lock.txt",
|
||||
requirements_windows = "//:requirements_windows_lock.txt",
|
||||
# compile_pip_requirements does not respect target_compatible_with for some of the targets it generates under the hood
|
||||
tags = ["no-systemcore"],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "quickbuf_protoc",
|
||||
actual = select({
|
||||
"@platforms//os:windows": "@quickbuffer_protoc_windows//file",
|
||||
"@rules_bzlmodrio_toolchains//conditions:osx_aarch64": "@quickbuffer_protoc_osx_aarch64//file",
|
||||
"@rules_bzlmodrio_toolchains//conditions:osx_x86_64": "@quickbuffer_protoc_osx_x86-64//file",
|
||||
"@rules_bzlmodrio_toolchains//constraints/combined:is_linux": "@quickbuffer_protoc_linux//file",
|
||||
}),
|
||||
tags = ["pregeneration"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# This is a helper to run all of the pregeneration scripts at once.
|
||||
write_source_files(
|
||||
name = "write_all",
|
||||
additional_update_targets = [
|
||||
"//hal:write_hal",
|
||||
"//ntcore:write_ntcore",
|
||||
"//wpilibc:write_wpilibc",
|
||||
"//wpilibcExamples:write_example_project_list",
|
||||
"//wpilibj:write_wpilibj",
|
||||
"//wpilibjExamples:write_example_project_list",
|
||||
"//wpilibNewCommands:write_wpilib_new_commands",
|
||||
"//commandsv3:write_commandsv3",
|
||||
"//wpimath:write_wpimath",
|
||||
"//wpiunits:write_wpiunits",
|
||||
"//wpiutil:write_wpiutil",
|
||||
],
|
||||
tags = ["pregeneration"],
|
||||
)
|
||||
|
||||
publish_all(
|
||||
name = "publish",
|
||||
targets = [
|
||||
"//apriltag:apriltag-cpp_publish.publish",
|
||||
"//apriltag:apriltag-java_publish.publish",
|
||||
"//cameraserver:cameraserver-cpp_publish.publish",
|
||||
"//cameraserver:cameraserver-java_publish.publish",
|
||||
"//cscore:cscore-cpp_publish.publish",
|
||||
"//cscore:cscore-java_publish.publish",
|
||||
"//datalog:datalog-cpp_publish.publish",
|
||||
"//datalog:datalog-java_publish.publish",
|
||||
"//datalogtool:datalogtool_publish.publish",
|
||||
"//docs:wpilibj_publish.publish",
|
||||
"//epilogue-processor:processor-java_publish.publish",
|
||||
"//epilogue-runtime:epilogue-java_publish.publish",
|
||||
"//fieldImages:fieldImages-cpp_publish.publish",
|
||||
"//fieldImages:fieldImages-java_publish.publish",
|
||||
"//glass:glass-cpp_publish.publish",
|
||||
"//glass:glassapp_publish.publish",
|
||||
"//glass:glassnt-cpp_publish.publish",
|
||||
"//hal:hal-java_publish.publish",
|
||||
"//hal:wpiHal-cpp_publish.publish",
|
||||
"//ntcore:ntcore-cpp_publish.publish",
|
||||
"//ntcore:ntcore-java_publish.publish",
|
||||
"//ntcoreffi:ntcoreffi-cpp_publish.publish",
|
||||
"//outlineviewer:outlineviewer_publish.publish",
|
||||
"//processstarter:processstarter_publish.publish",
|
||||
"//romiVendordep:romiVendordep-cpp_publish.publish",
|
||||
"//romiVendordep:romiVendordep-java_publish.publish",
|
||||
"//simulation/halsim_ds_socket:halsim_ds_socket-cpp_publish.publish",
|
||||
"//simulation/halsim_gui:halsim_gui-cpp_publish.publish",
|
||||
"//simulation/halsim_ws_client:halsim_ws_client-cpp_publish.publish",
|
||||
"//simulation/halsim_ws_core:halsim_ws_core-cpp_publish.publish",
|
||||
"//simulation/halsim_ws_server:halsim_ws_server-cpp_publish.publish",
|
||||
"//simulation/halsim_xrp:halsim_xrp-cpp_publish.publish",
|
||||
"//sysid:sysid_publish.publish",
|
||||
"//thirdparty/googletest:googletest-cpp_publish.publish",
|
||||
"//thirdparty/imgui_suite:imguiSuite-cpp_publish.publish",
|
||||
"//wpical:wpical_publish.publish",
|
||||
"//wpigui:wpigui-cpp_publish.publish",
|
||||
"//wpilibNewCommands:wpilibNewCommands-cpp_publish.publish",
|
||||
"//wpilibNewCommands:wpilibNewCommands-java_publish.publish",
|
||||
"//commandsv3:commandsv3-java_publish.publish",
|
||||
"//wpilibc:wpilibc-cpp_publish.publish",
|
||||
"//wpilibcExamples:commands_publish.publish",
|
||||
"//wpilibcExamples:examples_publish.publish",
|
||||
"//wpilibcExamples:templates_publish.publish",
|
||||
"//wpilibj:wpilibj-java_publish.publish",
|
||||
"//wpilibjExamples:commands_publish.publish",
|
||||
"//wpilibjExamples:examples_publish.publish",
|
||||
"//wpilibjExamples:templates_publish.publish",
|
||||
"//wpimath:wpimath-cpp_publish.publish",
|
||||
"//wpimath:wpimath-java_publish.publish",
|
||||
"//wpinet:wpinet-cpp_publish.publish",
|
||||
"//wpinet:wpinet-java_publish.publish",
|
||||
"//wpiunits:wpiunits-java_publish.publish",
|
||||
"//wpiutil:wpiutil-cpp_publish.publish",
|
||||
"//wpiutil:wpiutil-java_publish.publish",
|
||||
"//xrpVendordep:xrpVendordep-cpp_publish.publish",
|
||||
"//xrpVendordep:xrpVendordep-java_publish.publish",
|
||||
] + select({
|
||||
"@platforms//cpu:x86_64": [
|
||||
"//docs:wpilibc_publish.publish",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
@@ -90,6 +90,7 @@ option(WITH_EXAMPLES "Build examples" OFF)
|
||||
option(WITH_TESTS "Build unit tests (requires internet connection)" ON)
|
||||
option(WITH_GUI "Build GUI items" ON)
|
||||
option(WITH_SIMULATION_MODULES "Build simulation modules" ON)
|
||||
option(WITH_PROTOBUF "Build protobuf support" ON)
|
||||
option(WITH_BENCHMARK "Build the benchmark project" ON)
|
||||
|
||||
# Options for using a package manager (e.g., vcpkg) for certain dependencies.
|
||||
@@ -150,6 +151,14 @@ endif()
|
||||
|
||||
find_package(LIBSSH CONFIG 0.7.1)
|
||||
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
|
||||
if(WITH_PROTOBUF)
|
||||
set(protobuf_MODULE_COMPATIBLE ON CACHE BOOL "" FORCE)
|
||||
find_package(Protobuf REQUIRED)
|
||||
find_program(PROTOC_COMPILER protoc REQUIRED)
|
||||
endif()
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF)
|
||||
|
||||
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
|
||||
if(isMultiConfig)
|
||||
@@ -267,9 +276,6 @@ if(WITH_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(thirdparty/googletest)
|
||||
include(GoogleTest)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/catch2/extras")
|
||||
add_subdirectory(thirdparty/catch2)
|
||||
include(Catch)
|
||||
endif()
|
||||
|
||||
if(USE_SYSTEM_LIBUV)
|
||||
@@ -285,11 +291,8 @@ set(SELF_DIR "$\{SELF_DIR\}")
|
||||
set(WPIUNITS_DEP_REPLACE_IMPL "find_dependency(wpiunits)")
|
||||
set(WPIANNOTATIONS_DEP_REPLACE_IMPL "find_dependency(wpiannotations)")
|
||||
set(WPIUTIL_DEP_REPLACE "find_dependency(wpiutil)")
|
||||
set(DATALOG_DEP_REPLACE "find_dependency(datalog)")
|
||||
add_subdirectory(wpiutil)
|
||||
|
||||
add_subdirectory(datalog)
|
||||
|
||||
if(WITH_NTCORE)
|
||||
set(NTCORE_DEP_REPLACE "find_dependency(ntcore)")
|
||||
set(WPINET_DEP_REPLACE "find_dependency(wpinet)")
|
||||
@@ -327,6 +330,7 @@ if(WITH_GUI)
|
||||
add_subdirectory(wpical)
|
||||
endif()
|
||||
if(LIBSSH_FOUND)
|
||||
add_subdirectory(roborioteamnumbersetter)
|
||||
add_subdirectory(datalogtool)
|
||||
endif()
|
||||
endif()
|
||||
@@ -346,14 +350,14 @@ endif()
|
||||
|
||||
if(WITH_WPILIB)
|
||||
set(APRILTAG_DEP_REPLACE "find_dependency(apriltag)")
|
||||
set(COMMANDSV3_DEP_REPLACE "find_dependency(commandsv3)")
|
||||
set(WPILIBC_DEP_REPLACE "find_dependency(wpilibc)")
|
||||
set(WPILIBJ_DEP_REPLACE "find_dependency(wpilibj)")
|
||||
if(WITH_JAVA)
|
||||
set(WPILIBJ_DEP_REPLACE "find_dependency(wpilibj)")
|
||||
endif()
|
||||
set(WPILIBNEWCOMMANDS_DEP_REPLACE "find_dependency(wpilibNewCommands)")
|
||||
add_subdirectory(apriltag)
|
||||
add_subdirectory(wpilibj)
|
||||
add_subdirectory(wpilibc)
|
||||
add_subdirectory(commandsv3) # must be after wpilibj
|
||||
add_subdirectory(wpilibNewCommands)
|
||||
add_subdirectory(romiVendordep)
|
||||
add_subdirectory(xrpVendordep)
|
||||
|
||||
@@ -13,7 +13,7 @@ This article contains instructions on building projects using a development buil
|
||||
|
||||
Development builds are the per-commit build hosted every time a commit is pushed to the [allwpilib](https://github.com/wpilibsuite/allwpilib/) repository. These builds are then hosted on [artifactory](https://frcmaven.wpi.edu/artifactory/webapp/#/home).
|
||||
|
||||
To build a project using a development build, find the build.gradle file and open it. Then, add the following code below the plugin section and replace YEAR with the year of the development version. It is also necessary to use a 2025 GradleRIO version, ie `2025.1.1-beta-1`
|
||||
To build a project using a development build, find the build.gradle file and open it. Then, add the following code below the plugin section and replace YEAR with the year of the development version. It is also necessary to use a 2026 GradleRIO version, ie `2026.1.1`
|
||||
|
||||
```groovy
|
||||
wpi.maven.useLocal = false
|
||||
@@ -28,13 +28,13 @@ Java
|
||||
```groovy
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2025.1.1-beta-1"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.1.1"
|
||||
}
|
||||
|
||||
wpi.maven.useLocal = false
|
||||
wpi.maven.useDevelopment = true
|
||||
wpi.versions.wpilibVersion = '2025.+'
|
||||
wpi.versions.wpimathVersion = '2025.+'
|
||||
wpi.versions.wpilibVersion = '2026.+'
|
||||
wpi.versions.wpimathVersion = '2026.+'
|
||||
```
|
||||
|
||||
C++
|
||||
@@ -42,13 +42,13 @@ C++
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2025.1.1-beta-1"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.1.1"
|
||||
}
|
||||
|
||||
wpi.maven.useLocal = false
|
||||
wpi.maven.useDevelopment = true
|
||||
wpi.versions.wpilibVersion = '2025.+'
|
||||
wpi.versions.wpimathVersion = '2025.+'
|
||||
wpi.versions.wpilibVersion = '2026.+'
|
||||
wpi.versions.wpimathVersion = '2026.+'
|
||||
```
|
||||
|
||||
### Development Build Documentation
|
||||
@@ -64,7 +64,7 @@ Java
|
||||
```groovy
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2025.1.1-beta-1"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.1.1"
|
||||
}
|
||||
|
||||
wpi.maven.useLocal = false
|
||||
@@ -78,7 +78,7 @@ C++
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2025.1.1-beta-1"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.1.1"
|
||||
}
|
||||
|
||||
wpi.maven.useLocal = false
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009-2025 FIRST and other WPILib contributors
|
||||
Copyright (c) 2009-2026 FIRST and other WPILib contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -23,32 +23,3 @@ Examples:
|
||||
build --local_ram_resources=HOST_RAM*.5 # Don't use more than half my RAM when building
|
||||
build --local_cpu_resources=HOST_CPUS-1 # Leave one core alone
|
||||
```
|
||||
|
||||
The default settings build all the release artifact variants relevant for your platform. The overall list of options ends up being, essentially, all the variants of (linux, osx, windows) x (debug, release) x (static, shared) x (aarch64, x86). OSX and Windows are hard to compile for from any other OS, so we by default build for your local OS and the system core, with all the variants.
|
||||
|
||||
This can be a bit expensive. If you would like to build a subset, you can specify the repo environmental variable, `WPI_PUBLISH_CLASSIFIER_FILTER`, and pick what you build for. The default is, in the .bazelrc file,
|
||||
```
|
||||
common --repo_env="WPI_PUBLISH_CLASSIFIER_FILTER=headers,sources,linuxsystemcore,linuxsystemcoredebug,linuxsystemcorestatic,linuxsystemcorestaticdebug,linuxx86-64,linuxx86-64debug,linuxx86-64static,linuxx86-64staticdebug,osxuniversal,osxuniversaldebug,osxuniversalstatic,osxuniversalstaticdebug,windowsarm64,windowsarm64debug,windowsarm64static,windowsarm64staticdebug,windowsx86-64,windowsx86-64debug,windowsx86-64static,windowsx86-64staticdebug"
|
||||
```
|
||||
|
||||
Modify this to your likings if you want to build less.
|
||||
|
||||
## Pregenerating Files
|
||||
allwpilib uses extensive use of pre-generating files that are later used to build C++ / Java libraries that are tracked by version control. Quite often,
|
||||
these pre-generation scripts use some configuration file to create multipile files inside of an output directory. While this process could be accomplished
|
||||
with a `genrule` that would require an explicit listing of every output file, which would be tedious to maintain as well as potentially confusing to people
|
||||
adding new features those libraries. Therefor, we use `@aspect_bazel_lib` and their `write_source_files` feature to generate these directories. In the event that the generation process creates more than a small handful of predictable files, a custom rule is written to generate the directory.
|
||||
|
||||
## Remote Caching
|
||||
One of the huge benefits of bazel is its remote caching ability. However, due to bazels strict build definitions it is hard to share remote cache artifacts between different computers unless our toolchains are fully hermetic, which means you are unlikely to be able to reuse the cache artifacts published from the `main` branch on your local machine like you might be able to with the `gradle` or `cmake` caches. Luckily the github actions CI machines are generally stable between runs and can reuse cache artifacts, and your local machine should remain stable, so if you set up a free buildbuddy account you can have your forks CI actions be able to use a personalized cache, as well as your local machine.
|
||||
|
||||
For the main `allwpilib` upstream, the cache is only updated on the main branch; pull requests from forks will not be able to modify the cache. However, you can set up your fork to enable its own cache by following the steps below.
|
||||
|
||||
### Setting Up API keys
|
||||
Follow the [buildbuddy authentication](https://www.buildbuddy.io/docs/guide-auth) guide to create keys. For your local machine, it is recommended that you place the following configuration line in either a `user.bazelrc` or `bazel_auth.rc` file in the repositories root directory.
|
||||
|
||||
```
|
||||
build --remote_header=<your api key>
|
||||
```
|
||||
|
||||
To get your forks CI actions using your own buildbuddy cache, follow [GitHub's](https://docs.github.com/en/actions/how-tos/security-for-github-actions/security-guides/using-secrets-in-github-actions) documentation for setting up a repository secret. The secrets key should be `BUILDBUDDY_API_KEY`, and the value should be your buildbuddy API key.
|
||||
|
||||
@@ -5,7 +5,6 @@ WPILib is normally built with Gradle, however for some systems, such as Linux ba
|
||||
## Libraries that get built
|
||||
* apriltag
|
||||
* cameraserver
|
||||
* commandsv3
|
||||
* cscore
|
||||
* fieldImages
|
||||
* hal (simulation HAL only)
|
||||
@@ -25,6 +24,7 @@ WPILib is normally built with Gradle, however for some systems, such as Linux ba
|
||||
* datalogtool
|
||||
* glass
|
||||
* outlineviewer
|
||||
* roborioteamnumbersetter
|
||||
* sysid
|
||||
* halsim_gui (if simulation extensions are enabled)
|
||||
|
||||
@@ -32,9 +32,11 @@ By default, all libraries get built with a default CMake setup. The libraries ar
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The protobuf library and compiler are needed for protobuf generation.
|
||||
|
||||
OpenCV needs to be findable by CMake. On systems like the Jetson, this is installed by default. Otherwise, you will need to build OpenCV from source and install it.
|
||||
|
||||
If you want JNI and Java, you will need a JDK of at least version 21 installed. In addition, you need a `JAVA_HOME` environment variable set properly and set to the JDK directory.
|
||||
If you want JNI and Java, you will need a JDK of at least version 17 installed. In addition, you need a `JAVA_HOME` environment variable set properly and set to the JDK directory.
|
||||
|
||||
If you are building with unit tests or simulation modules, you will also need an Internet connection for the initial setup process, as CMake will clone google-test and imgui from GitHub.
|
||||
|
||||
@@ -64,6 +66,8 @@ The following build options are available:
|
||||
* This option will build the HAL and wpilibc/j during the build. The HAL is the simulation HAL, unless the external HAL options are used. The CMake build has no capability to build for the roboRIO.
|
||||
* `WITH_WPIMATH` (ON Default)
|
||||
* This option will build the wpimath library. This option must be on to build wpilib.
|
||||
* `WITH_PROTOBUF` (ON Default)
|
||||
* This option will build with the protobuf library.
|
||||
* `WITH_WPIUNITS` (`WITH_JAVA` Default)
|
||||
* This option will build the wpiunits library. This option must be on to build the Java wpimath library and requires `WITH_JAVA` to also be on.
|
||||
* `OPENCV_JAVA_INSTALL_DIR`
|
||||
@@ -87,6 +91,8 @@ If you want to change any of the options, add `-DOPTIONHERE=VALUE` to the `cmake
|
||||
|
||||
If you want, you can also use `ccmake` in order to visually set these properties as well. [Here](https://cmake.org/cmake/help/v3.0/manual/ccmake.1.html) is the link to the documentation for that program. On Windows, you can use `cmake-gui` instead.
|
||||
|
||||
Note that if you are cross-compiling, you will need to override the protobuf options manually to point to the libraries for the target platform. Leave the protoc binary location as the path to the binary for the host platform, since protoc needs to execute on the host platform.
|
||||
|
||||
## Presets
|
||||
|
||||
The WPILib CMake setup has a variety of presets for common configurations and options used. The default sets the generator to Ninja and build directory to `build-cmake`. The other presets are `with-java` (sets `WITH_JAVA=ON`), `sccache` (sets the C/C++ compiler launcher to sccache), and `with-java-sccache` (a comibination of `with-java` and `sccache`.
|
||||
@@ -113,7 +119,7 @@ sudo cmake --build . --target install
|
||||
|
||||
## Preparing to use the installed libraries
|
||||
|
||||
On Windows, make sure the directories for the libraries you built are on PATH. For wpilib, the default install location is `C:\Program Files (x86)\allwpilib`. If you built other libraries like OpenCV from source, install them, and add the install directories to PATH. This ensures CMake can locate the libraries.
|
||||
On Windows, make sure the directories for the libraries you built are on PATH. For wpilib, the default install location is `C:\Program Files (x86)\allwpilib`. If you built other libraries like OpenCV and protobuf from source, install them, and add the install directories to PATH. This ensures CMake can locate the libraries.
|
||||
|
||||
You will also want to add the directories where the DLLs are located (usually the `bin` subdirectory of the install directory) to PATH so they can be loaded by your program. If you are using OpenCV and Java, the `opencv_java` DLL is located in either the `lib` subdirectory if you built but didn't install OpenCV, or the `java` subdirectory if you did install OpenCV.
|
||||
|
||||
@@ -229,6 +235,6 @@ Last Load Error:
|
||||
C:\Program Files (x86)\allwpilib\bin\wpiHaljni.dll: Can't find dependent libraries
|
||||
```
|
||||
|
||||
If you get this error, that's usually an indication that not all your libraries are in your PATH. If the error is coming from cscore specifically, it's likely you're missing OpenCV. Otherwise, it's likely the wpilib libraries are not in a directory on PATH.
|
||||
If you get this error, that's usually an indication that not all your libraries are in your PATH. The two libraries that should be in your PATH are OpenCV and protobuf. If the error is coming from cscore, it's likely you're missing OpenCV. Otherwise, it's likely you're missing protobuf.
|
||||
|
||||
Note that Linux will not have this specific type of error, as it will usually tell you the dependent library you are missing. In that case, you most likely need to add the library to `LD_LIBRARY_PATH`.
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# robotpy in allwpilb
|
||||
allwpilib hosts a mirror of RobotPy that can be built with bazel on Linux. The intent of the mirror is to have breaking changes identified early and fixed by the PR creator so that when wpilib releases are made there is much less work required to release a RobotPy version that wraps it. It is not a goal for allwpilib to replace the RobotPy repo; it will still be considered the "source of truth" for python builds and will be responsible for building against all of the applicable architectures and multiple versions of python.
|
||||
|
||||
## Build Process
|
||||
The upstream RobotPy repository uses toml configuration files and semiwrap to produce Meson build scripts. The allwpilib fork uses these toml configuration files to auto generate bazel build scripts. In general, each project (wpiutil, wpimath, etc) defines two pybind extensions; one that simply wraps the native library, and another that adds extension(s) that and contains all of the python files for the library. Both of these subprojects have auto-generated build files; a `robotpy_native_build_info.bzl` for the lidar wraper and `robotpy_pybind_build_info.bzl` which defines the extensions and python library.
|
||||
|
||||
## Disabling robotpy builds
|
||||
Building the robotpy software on top of the standard C++/Java software can result in more than doubling the amount of time it takes to compile. To skip building the robotpy tooling you can add `--config=skip_robotpy` to the command line or to your `user.bazelrc`
|
||||
|
||||
# Syncing with robotpy
|
||||
NOTE: This process is currently unlanded while robotpy gets the 2027 branch stable
|
||||
|
||||
[Copybara](https://github.com/google/copybara) is used to maintin synchronization between the upstream robotpy repositories and the allwpilib mirror. Github actions can be manually run which will create pull requests that will update all of the robotpy files between the two repositories. The ideal process is that the allwpilib mirror is always building in CI, and once a release is created the RobotPy team can run the `wpilib -> robotpy` copybara task, make any fine tuned adjustements and create their release. In the event that additional changes are made on the robotpy side, they can run the `robotpy -> wpilib` task to push the updates back to the mirror. However the goal of the mirroring the software here is to be able to more rapidly test changes and will hopefully overwhelmingly eliminate the need for syncs this direction.
|
||||
17
README.md
17
README.md
@@ -42,30 +42,23 @@ Using Gradle makes building WPILib very straightforward. It only has a few depen
|
||||
|
||||
## Requirements
|
||||
|
||||
- [JDK 21](https://adoptium.net/temurin/releases/?version=21)
|
||||
- [JDK 17](https://adoptium.net/temurin/releases/?version=17)
|
||||
- Note that the JRE is insufficient; the full JDK is required
|
||||
- On Ubuntu, run `sudo apt install openjdk-21-jdk`
|
||||
- On Windows, install the JDK 21 .msi from the link above
|
||||
- On macOS, install the JDK 21 .pkg from the link above
|
||||
- On Ubuntu, run `sudo apt install openjdk-17-jdk`
|
||||
- On Windows, install the JDK 17 .msi from the link above
|
||||
- On macOS, install the JDK 17 .pkg from the link above
|
||||
- C++ compiler
|
||||
- On Linux, install GCC 11 or greater
|
||||
- On Windows, install [Visual Studio Community 2022](https://visualstudio.microsoft.com/vs/community/) and select the C++ programming language during installation (Gradle can't use the build tools for Visual Studio)
|
||||
- On macOS 13.3 or newer, install Xcode 14 or later (the command-line build tools are insufficient).
|
||||
- On macOS, install the Xcode command-line build tools via `xcode-select --install`. Xcode 14 or later is required.
|
||||
- ARM compiler toolchain
|
||||
- Run `./gradlew installRoboRioToolchain` after cloning this repository
|
||||
- If the WPILib installer was used, this toolchain is already installed
|
||||
- Raspberry Pi toolchain (optional)
|
||||
- Run `./gradlew installArm32Toolchain` after cloning this repository
|
||||
- SystemCore toolchain (required for SystemCore development)
|
||||
- Run `./gradlew installSystemCoreToolchain` after cloning this repository
|
||||
- If the WPILib installer was used, this toolchain is already installed
|
||||
|
||||
On macOS ARM, run `softwareupdate --install-rosetta`. This is necessary to be able to use the macOS x86 roboRIO toolchain on ARM.
|
||||
|
||||
On linux, run `sudo apt install gfortran`. This is necessary to be able to build WPIcal on linux platforms.
|
||||
|
||||
On linux, run `sudo apt install libx11-dev libgl-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev` to be able to build things depending on glfw.
|
||||
|
||||
## Setup
|
||||
|
||||
Clone the WPILib repository and follow the instructions above for installing any required tooling. The build process uses versioning information from git. Downloading the source is not sufficient to run the build.
|
||||
|
||||
@@ -49,10 +49,10 @@ glfw thirdparty/imgui_suite/glfw
|
||||
Dear ImGui thirdparty/imgui_suite/imgui
|
||||
implot thirdparty/imgui_suite/implot
|
||||
nanopb wpiutil/src/main/native/thirdparty/nanopb
|
||||
upb wpiutil/src/main/native/thirdparty/upb
|
||||
protobuf wpiutil/src/main/native/thirdparty/protobuf
|
||||
mrcal wpical/src/main/native/thirdparty/mrcal
|
||||
libdogleg wpical/src/main/native/thirdparty/libdogleg
|
||||
Simd hal/src/main/native/systemcore/simd
|
||||
Simd hal/src/main/native/athena/simd
|
||||
|
||||
Additionally, glfw and nanopb were modified for use in WPILib.
|
||||
|
||||
@@ -1355,7 +1355,7 @@ redistribute it freely, subject to the following restrictions:
|
||||
distribution.
|
||||
|
||||
================
|
||||
upb License
|
||||
protobuf License
|
||||
================
|
||||
Copyright 2008 Google Inc. All rights reserved.
|
||||
|
||||
|
||||
387
WORKSPACE
387
WORKSPACE
@@ -1,189 +1,18 @@
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")
|
||||
load("//thirdparty/ceres:repositories.bzl", "ceres_repositories")
|
||||
|
||||
ceres_repositories()
|
||||
|
||||
http_archive(
|
||||
name = "bazel_features",
|
||||
sha256 = "a015f3f2ebf4f1ac3f4ca8ea371610acb63e1903514fa8725272d381948d2747",
|
||||
strip_prefix = "bazel_features-1.31.0",
|
||||
url = "https://github.com/bazel-contrib/bazel_features/releases/download/v1.31.0/bazel_features-v1.31.0.tar.gz",
|
||||
)
|
||||
|
||||
# TODO(austin): Upgrade when the patches land.
|
||||
# https://github.com/bazelbuild/rules_cc/pull/430
|
||||
# https://github.com/bazelbuild/rules_cc/pull/431
|
||||
# https://github.com/bazelbuild/rules_cc/pull/432
|
||||
http_archive(
|
||||
name = "rules_cc",
|
||||
patch_args = ["-p1"],
|
||||
patches = ["//:shared/bazel/patches/rules_cc_windows.patch"],
|
||||
sha256 = "0d3b4f984c4c2e1acfd1378e0148d35caf2ef1d9eb95b688f8e19ce0c41bdf5b",
|
||||
strip_prefix = "rules_cc-0.1.4",
|
||||
url = "https://github.com/bazelbuild/rules_cc/releases/download/0.1.4/rules_cc-0.1.4.tar.gz",
|
||||
)
|
||||
|
||||
# TODO(austinschuh): Update to the next released apple_support once it lands.
|
||||
# This needs to contain https://github.com/bazelbuild/apple_support/commit/7009b77c98a67d3fea081c9db4dbcee8effc3b7e and should be the next release after 1.22.1
|
||||
http_archive(
|
||||
name = "build_bazel_apple_support",
|
||||
sha256 = "7d542be113180bc1da3660e51fe4792a867fb85537c9ef36a0d3366665a76803",
|
||||
strip_prefix = "apple_support-7009b77c98a67d3fea081c9db4dbcee8effc3b7e",
|
||||
url = "https://github.com/bazelbuild/apple_support/archive/7009b77c98a67d3fea081c9db4dbcee8effc3b7e.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "rules_java",
|
||||
sha256 = "d31b6c69e479ffa45460b64dc9c7792a431cac721ef8d5219fc9f603fa2ff877",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/rules_java/releases/download/8.11.0/rules_java-8.11.0.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "rules_pkg",
|
||||
sha256 = "cad05f864a32799f6f9022891de91ac78f30e0fa07dc68abac92a628121b5b11",
|
||||
urls = [
|
||||
"https://github.com/bazelbuild/rules_pkg/releases/download/1.0.0/rules_pkg-1.0.0.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
# Rules Python
|
||||
http_archive(
|
||||
name = "rules_python",
|
||||
sha256 = "9f9f3b300a9264e4c77999312ce663be5dee9a56e361a1f6fe7ec60e1beef9a3",
|
||||
strip_prefix = "rules_python-1.4.1",
|
||||
url = "https://github.com/bazel-contrib/rules_python/releases/download/1.4.1/rules_python-1.4.1.tar.gz",
|
||||
)
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
# Download Extra java rules
|
||||
http_archive(
|
||||
name = "rules_jvm_external",
|
||||
sha256 = "4f55980c25d0783b9fe43b049362018d8d79263476b5340a5491893ffcc06ab6",
|
||||
strip_prefix = "rules_jvm_external-30899314873b6ec69dc7d02c4457fbe52a6e535d",
|
||||
url = "https://github.com/bazel-contrib/rules_jvm_external/archive/30899314873b6ec69dc7d02c4457fbe52a6e535d.tar.gz",
|
||||
sha256 = "08ea921df02ffe9924123b0686dc04fd0ff875710bfadb7ad42badb931b0fd50",
|
||||
strip_prefix = "rules_jvm_external-6.1",
|
||||
url = "https://github.com/bazelbuild/rules_jvm_external/releases/download/6.1/rules_jvm_external-6.1.tar.gz",
|
||||
)
|
||||
|
||||
# Setup aspect lib
|
||||
http_archive(
|
||||
name = "aspect_bazel_lib",
|
||||
sha256 = "a8a92645e7298bbf538aa880131c6adb4cf6239bbd27230f077a00414d58e4ce",
|
||||
strip_prefix = "bazel-lib-2.7.2",
|
||||
url = "https://github.com/aspect-build/bazel-lib/releases/download/v2.7.2/bazel-lib-v2.7.2.tar.gz",
|
||||
)
|
||||
|
||||
# Download toolchains
|
||||
http_archive(
|
||||
name = "rules_bzlmodrio_toolchains",
|
||||
sha256 = "102b4507628e9724b0c1e441727762c344e40170f65ac60516168178ea33a89a",
|
||||
url = "https://github.com/wpilibsuite/rules_bzlmodrio_toolchains/releases/download/2025-1.bcr6/rules_bzlmodrio_toolchains-2025-1.bcr6.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "pybind11_bazel",
|
||||
integrity = "sha256-iwRj1wuX2pDS6t6DqiCfhIXisv4y+7CvxSJtZoSAzGw=",
|
||||
strip_prefix = "pybind11_bazel-2b6082a4d9d163a52299718113fa41e4b7978db5",
|
||||
urls = ["https://github.com/pybind/pybind11_bazel/archive/2b6082a4d9d163a52299718113fa41e4b7978db5.tar.gz"],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "pybind11",
|
||||
build_file = "@pybind11_bazel//:pybind11-BUILD.bazel",
|
||||
strip_prefix = "pybind11-dfe7e65b4527eeb11036402aac3a394130960bb2",
|
||||
urls = ["https://github.com/pybind/pybind11/archive/dfe7e65b4527eeb11036402aac3a394130960bb2.zip"],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "rules_python_pytest",
|
||||
sha256 = "e2556404ef56ea3ec938597616afc51d78e1832cfe511b196e9f2b8fd7f8f149",
|
||||
strip_prefix = "rules_python_pytest-1.1.1",
|
||||
url = "https://github.com/caseyduquettesc/rules_python_pytest/releases/download/v1.1.1/rules_python_pytest-v1.1.1.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "bazel_skylib",
|
||||
sha256 = "51b5105a760b353773f904d2bbc5e664d0987fbaf22265164de65d43e910d8ac",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.8.1/bazel-skylib-1.8.1.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.8.1/bazel-skylib-1.8.1.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "rules_doxygen",
|
||||
sha256 = "5d154d3d011208510392b5aee8ea23ec61ab858cc1f3382b6eb8c729d3b4b336",
|
||||
strip_prefix = "rules_doxygen-2.4.2",
|
||||
url = "https://github.com/TendTo/rules_doxygen/releases/download/2.4.2/rules_doxygen-2.4.2.tar.gz",
|
||||
)
|
||||
|
||||
# This gives us a repository layout which matches what normal BCR modules expect.
|
||||
# The goal here is to make it easier to depend on external projects which already
|
||||
# include @eigen without introducing multiple eigen versions.
|
||||
local_repository(
|
||||
name = "eigen",
|
||||
path = "wpimath/src/main/native/thirdparty/eigen/include/",
|
||||
)
|
||||
|
||||
load("@bazel_features//:deps.bzl", "bazel_features_deps")
|
||||
|
||||
bazel_features_deps()
|
||||
|
||||
load("@build_bazel_apple_support//lib:repositories.bzl", "apple_support_dependencies")
|
||||
|
||||
apple_support_dependencies()
|
||||
|
||||
load("@rules_cc//cc:repositories.bzl", "rules_cc_toolchains")
|
||||
|
||||
rules_cc_toolchains()
|
||||
|
||||
load("@rules_java//java:rules_java_deps.bzl", "rules_java_dependencies")
|
||||
|
||||
rules_java_dependencies()
|
||||
|
||||
# note that the following line is what is minimally required from protobuf for the java rules
|
||||
# consider using the protobuf_deps() public API from @com_google_protobuf//:protobuf_deps.bzl
|
||||
load("@com_google_protobuf//bazel/private:proto_bazel_features.bzl", "proto_bazel_features") # buildifier: disable=bzl-visibility
|
||||
|
||||
proto_bazel_features(name = "proto_bazel_features")
|
||||
|
||||
# register toolchains
|
||||
load("@rules_java//java:repositories.bzl", "rules_java_toolchains")
|
||||
|
||||
rules_java_toolchains()
|
||||
|
||||
load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")
|
||||
|
||||
py_repositories()
|
||||
|
||||
python_register_toolchains(
|
||||
name = "python_3_10",
|
||||
ignore_root_user_error = True,
|
||||
python_version = "3.10",
|
||||
)
|
||||
|
||||
load("@rules_python//python:pip.bzl", "pip_parse")
|
||||
|
||||
pip_parse(
|
||||
name = "allwpilib_pip_deps",
|
||||
python_interpreter_target = "@python_3_10_host//:python",
|
||||
requirements_lock = "//:requirements_lock.txt",
|
||||
requirements_windows = "//:requirements_windows_lock.txt",
|
||||
)
|
||||
|
||||
load("@allwpilib_pip_deps//:requirements.bzl", "install_deps")
|
||||
|
||||
install_deps()
|
||||
|
||||
load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
|
||||
|
||||
rules_jvm_external_deps()
|
||||
|
||||
load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
|
||||
|
||||
rules_jvm_external_setup()
|
||||
|
||||
load("@rules_jvm_external//:defs.bzl", "maven_install")
|
||||
load("@rules_jvm_external//:specs.bzl", "maven")
|
||||
|
||||
maven_artifacts = [
|
||||
"org.ejml:ejml-simple:0.44.0",
|
||||
@@ -192,94 +21,23 @@ maven_artifacts = [
|
||||
"com.fasterxml.jackson.core:jackson-databind:2.19.2",
|
||||
"us.hebi.quickbuf:quickbuf-runtime:1.4",
|
||||
"com.google.code.gson:gson:2.13.1",
|
||||
"edu.wpi.first.thirdparty.frc2025.opencv:opencv-java:4.10.0-3",
|
||||
maven.artifact(
|
||||
"org.junit.jupiter",
|
||||
"junit-jupiter",
|
||||
"5.10.1",
|
||||
testonly = True,
|
||||
),
|
||||
maven.artifact(
|
||||
"org.junit.platform",
|
||||
"junit-platform-console",
|
||||
"1.10.1",
|
||||
testonly = True,
|
||||
),
|
||||
maven.artifact(
|
||||
"org.junit.platform",
|
||||
"junit-platform-launcher",
|
||||
"1.10.1",
|
||||
testonly = True,
|
||||
),
|
||||
maven.artifact(
|
||||
"org.junit.platform",
|
||||
"junit-platform-reporting",
|
||||
"1.10.1",
|
||||
testonly = True,
|
||||
),
|
||||
maven.artifact(
|
||||
"com.google.code.gson",
|
||||
"gson",
|
||||
"2.10.1",
|
||||
testonly = False,
|
||||
),
|
||||
maven.artifact(
|
||||
"org.hamcrest",
|
||||
"hamcrest-all",
|
||||
"1.3",
|
||||
testonly = True,
|
||||
),
|
||||
maven.artifact(
|
||||
"com.googlecode.junit-toolbox",
|
||||
"junit-toolbox",
|
||||
"2.4",
|
||||
testonly = True,
|
||||
),
|
||||
maven.artifact(
|
||||
"org.apache.ant",
|
||||
"ant",
|
||||
"1.10.12",
|
||||
testonly = True,
|
||||
),
|
||||
maven.artifact(
|
||||
"org.apache.ant",
|
||||
"ant-junit",
|
||||
"1.10.12",
|
||||
testonly = True,
|
||||
),
|
||||
maven.artifact(
|
||||
"org.mockito",
|
||||
"mockito-core",
|
||||
"4.1.0",
|
||||
testonly = True,
|
||||
),
|
||||
maven.artifact(
|
||||
"com.google.testing.compile",
|
||||
"compile-testing",
|
||||
"0.21.0",
|
||||
testonly = True,
|
||||
),
|
||||
]
|
||||
|
||||
maven_install(
|
||||
name = "maven",
|
||||
artifacts = maven_artifacts,
|
||||
maven_install_json = "//:maven_install.json",
|
||||
repositories = [
|
||||
"https://repo1.maven.org/maven2",
|
||||
"https://frcmaven.wpi.edu/artifactory/release/",
|
||||
],
|
||||
)
|
||||
|
||||
load("@maven//:defs.bzl", "pinned_maven_install")
|
||||
|
||||
pinned_maven_install()
|
||||
|
||||
load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies", "aspect_bazel_lib_register_toolchains")
|
||||
|
||||
aspect_bazel_lib_dependencies()
|
||||
|
||||
aspect_bazel_lib_register_toolchains()
|
||||
# Download toolchains
|
||||
http_archive(
|
||||
name = "rules_bzlmodrio_toolchains",
|
||||
sha256 = "ff25b5f9445cbd43759be4c6582b987d1065cf817c593eedc7ada1a699298c84",
|
||||
url = "https://github.com/wpilibsuite/rules_bzlmodRio_toolchains/releases/download/2025-1.bcr2/rules_bzlmodRio_toolchains-2025-1.bcr2.tar.gz",
|
||||
)
|
||||
|
||||
load("@rules_bzlmodrio_toolchains//:maven_deps.bzl", "setup_legacy_setup_toolchains_dependencies")
|
||||
|
||||
@@ -292,8 +50,8 @@ load_toolchains()
|
||||
#
|
||||
http_archive(
|
||||
name = "rules_bzlmodrio_jdk",
|
||||
sha256 = "623b8bcdba1c3140f56e940365f011d2e5d90d74c7a30ace6a8817c037c1dd61",
|
||||
url = "https://github.com/wpilibsuite/rules_bzlmodRio_jdk/releases/download/17.0.12-7.bcr1/rules_bzlmodrio_jdk-17.0.12-7.bcr1.tar.gz",
|
||||
sha256 = "81869fe9860e39b17e4a9bc1d33c1ca2faede7e31d9538ed0712406f753a2163",
|
||||
url = "https://github.com/wpilibsuite/rules_bzlmodRio_jdk/releases/download/17.0.12-7/rules_bzlmodRio_jdk-17.0.12-7.tar.gz",
|
||||
)
|
||||
|
||||
load("@rules_bzlmodrio_jdk//:maven_deps.bzl", "setup_legacy_setup_jdk_dependencies")
|
||||
@@ -307,9 +65,18 @@ register_toolchains(
|
||||
"@local_systemcore//:macos",
|
||||
"@local_systemcore//:linux",
|
||||
"@local_systemcore//:windows",
|
||||
"@local_raspi_bullseye_32//:macos",
|
||||
"@local_raspi_bullseye_32//:linux",
|
||||
"@local_raspi_bullseye_32//:windows",
|
||||
"@local_raspi_bookworm_32//:macos",
|
||||
"@local_raspi_bookworm_32//:linux",
|
||||
"@local_raspi_bookworm_32//:windows",
|
||||
"@local_bullseye_32//:macos",
|
||||
"@local_bullseye_32//:linux",
|
||||
"@local_bullseye_32//:windows",
|
||||
"@local_bullseye_64//:macos",
|
||||
"@local_bullseye_64//:linux",
|
||||
"@local_bullseye_64//:windows",
|
||||
"@local_bookworm_32//:macos",
|
||||
"@local_bookworm_32//:linux",
|
||||
"@local_bookworm_32//:windows",
|
||||
@@ -332,113 +99,27 @@ setup_legacy_bzlmodrio_ni_cpp_dependencies()
|
||||
|
||||
http_archive(
|
||||
name = "bzlmodrio-opencv",
|
||||
sha256 = "867ec3e90b7efc30ff6eb68d14050e7f1e800656d390505b135069f080c5cd91",
|
||||
url = "https://github.com/wpilibsuite/bzlmodRio-opencv/releases/download/2025.4.10.0-3.bcr5/bzlmodRio-opencv-2025.4.10.0-3.bcr5.tar.gz",
|
||||
sha256 = "ba3f4910ce9cc0e08abff732aeb5835b1bcfd864ca5296edeadcf2935f7e81b9",
|
||||
url = "https://github.com/wpilibsuite/bzlmodRio-opencv/releases/download/2025.4.10.0-3.bcr1/bzlmodRio-opencv-2025.4.10.0-3.bcr1.tar.gz",
|
||||
)
|
||||
|
||||
load("@bzlmodrio-opencv//:maven_cpp_deps.bzl", "setup_legacy_bzlmodrio_opencv_cpp_dependencies")
|
||||
|
||||
setup_legacy_bzlmodrio_opencv_cpp_dependencies()
|
||||
|
||||
load("@bzlmodrio-opencv//:maven_java_deps.bzl", "setup_legacy_bzlmodrio_opencv_java_dependencies")
|
||||
|
||||
setup_legacy_bzlmodrio_opencv_java_dependencies()
|
||||
|
||||
http_archive(
|
||||
name = "bzlmodrio-libssh",
|
||||
sha256 = "f8fef627c7b393f7f6ed638e12b80ff90b2cfea11488b15214f25ce1e470723a",
|
||||
url = "https://github.com/wpilibsuite/bzlmodRio-libssh/releases/download/2024.0.105-1.bcr1/bzlmodrio-libssh-2024.0.105-1.bcr1.tar.gz",
|
||||
name = "build_bazel_apple_support",
|
||||
sha256 = "c4bb2b7367c484382300aee75be598b92f847896fb31bbd22f3a2346adf66a80",
|
||||
url = "https://github.com/bazelbuild/apple_support/releases/download/1.15.1/apple_support.1.15.1.tar.gz",
|
||||
)
|
||||
|
||||
load("@bzlmodrio-libssh//:maven_cpp_deps.bzl", "setup_legacy_bzlmodrio_libssh_cpp_dependencies")
|
||||
|
||||
setup_legacy_bzlmodrio_libssh_cpp_dependencies()
|
||||
|
||||
# Setup quickbuf compiler
|
||||
QUICKBUF_VERSION = "1.3.2"
|
||||
|
||||
http_file(
|
||||
name = "quickbuffer_protoc_linux",
|
||||
executable = True,
|
||||
sha256 = "f9a041bccaa7040db523666ef1b5fe9f6f94e70a82c88951f18f58aadd9c50b5",
|
||||
url = "https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/" + QUICKBUF_VERSION + "/protoc-gen-quickbuf-" + QUICKBUF_VERSION + "-linux-x86_64.exe",
|
||||
load(
|
||||
"@build_bazel_apple_support//lib:repositories.bzl",
|
||||
"apple_support_dependencies",
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "quickbuffer_protoc_osx_x86-64",
|
||||
executable = True,
|
||||
sha256 = "ea307c2b69664ae7e7c69db4cddf5803187e5a34bceffd09a21652f0f16044f7",
|
||||
url = "https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/" + QUICKBUF_VERSION + "/protoc-gen-quickbuf-" + QUICKBUF_VERSION + "-osx-x86_64.exe ",
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "quickbuffer_protoc_osx_aarch64",
|
||||
executable = True,
|
||||
sha256 = "a9abdee09d8b5ef0aa954b238536917313511deec11e1901994af26ade033e28",
|
||||
url = "https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/" + QUICKBUF_VERSION + "/protoc-gen-quickbuf-" + QUICKBUF_VERSION + "-osx-aarch_64.exe ",
|
||||
)
|
||||
|
||||
http_file(
|
||||
name = "quickbuffer_protoc_windows",
|
||||
executable = True,
|
||||
sha256 = "27dc1f29764a62b5e6a813a4bcd63e81bbdc3394da760a44acae1025b4a89f1d",
|
||||
url = "https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/" + QUICKBUF_VERSION + "/protoc-gen-quickbuf-" + QUICKBUF_VERSION + "-windows-x86_64.exe ",
|
||||
)
|
||||
|
||||
# Setup rules_proto
|
||||
http_archive(
|
||||
name = "rules_proto",
|
||||
sha256 = "0e5c64a2599a6e26c6a03d6162242d231ecc0de219534c38cb4402171def21e8",
|
||||
strip_prefix = "rules_proto-7.0.2",
|
||||
url = "https://github.com/bazelbuild/rules_proto/releases/download/7.0.2/rules_proto-7.0.2.tar.gz",
|
||||
)
|
||||
|
||||
load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies")
|
||||
|
||||
rules_proto_dependencies()
|
||||
|
||||
load("@rules_proto//proto:setup.bzl", "rules_proto_setup")
|
||||
|
||||
rules_proto_setup()
|
||||
|
||||
load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies")
|
||||
|
||||
rules_pkg_dependencies()
|
||||
|
||||
load("@rules_python_pytest//python_pytest:repositories.bzl", "rules_python_pytest_dependencies")
|
||||
|
||||
rules_python_pytest_dependencies()
|
||||
|
||||
# Capture the repository environmental variables which specify the filter list for what architectures to build in CI.
|
||||
load("//shared/bazel/rules:publishing_rule.bzl", "publishing_repo")
|
||||
|
||||
publishing_repo(
|
||||
name = "com_wpilib_allwpilib_publishing_config",
|
||||
)
|
||||
|
||||
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
|
||||
|
||||
bazel_skylib_workspace()
|
||||
|
||||
load("@rules_doxygen//:extensions.bzl", "doxygen_repository")
|
||||
|
||||
# Download the os specific version 1.12.0 of doxygen supporting all the indicated platforms
|
||||
doxygen_repository(
|
||||
name = "doxygen",
|
||||
executables = [
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
],
|
||||
platforms = [
|
||||
"windows",
|
||||
"mac",
|
||||
"linux",
|
||||
],
|
||||
sha256s = [
|
||||
"07f1c92cbbb32816689c725539c0951f92c6371d3d7f66dfa3192cbe88dd3138",
|
||||
"6ace7dde967d41f4e293d034a67eb2c7edd61318491ee3131112173a77344001",
|
||||
"3c42c3f3fb206732b503862d9c9c11978920a8214f223a3950bbf2520be5f647",
|
||||
],
|
||||
versions = [
|
||||
"1.12.0",
|
||||
"1.12.0",
|
||||
"1.12.0",
|
||||
],
|
||||
)
|
||||
apple_support_dependencies()
|
||||
|
||||
@@ -1,41 +1,21 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
|
||||
load("@rules_java//java:defs.bzl", "java_binary")
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_files")
|
||||
load("@rules_java//java:defs.bzl", "java_binary", "java_library")
|
||||
load("@rules_python//python:defs.bzl", "py_binary")
|
||||
load("//shared/bazel/rules:cc_rules.bzl", "wpilib_cc_library", "wpilib_cc_shared_library", "wpilib_cc_static_library")
|
||||
load("//shared/bazel/rules:java_rules.bzl", "wpilib_java_junit5_test")
|
||||
load("//shared/bazel/rules:jni_rules.bzl", "wpilib_jni_cc_library", "wpilib_jni_java_library")
|
||||
load("//shared/bazel/rules:packaging.bzl", "package_minimal_jni_project")
|
||||
load("//shared/bazel/rules/gen:gen-resources.bzl", "generate_resources")
|
||||
|
||||
filegroup(
|
||||
name = "doxygen-files",
|
||||
srcs = glob([
|
||||
"src/main/native/include/**/*",
|
||||
"src/main/native/thirdparty/apriltag/include/**/*",
|
||||
]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "thirdparty-apriltag-src-pkg",
|
||||
srcs = glob(["src/main/native/thirdparty/apriltag/include/**"]),
|
||||
strip_prefix = "src/main/native/thirdparty/apriltag/include",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "thirdparty-apriltag",
|
||||
srcs = glob(["src/main/native/thirdparty/apriltag/src/**"]),
|
||||
hdrs = glob(["src/main/native/thirdparty/apriltag/include/**"]),
|
||||
copts = select({
|
||||
"@platforms//os:osx": [
|
||||
"@bazel_tools//src/conditions:darwin": [
|
||||
"-Wno-format-nonliteral",
|
||||
"-Wno-gnu-zero-variadic-macro-arguments",
|
||||
"-Wno-uninitialized",
|
||||
"-Wno-sign-compare",
|
||||
"-Wno-type-limits",
|
||||
],
|
||||
"@platforms//os:windows": [
|
||||
"@bazel_tools//src/conditions:windows": [
|
||||
"/wd4005",
|
||||
"/wd4018",
|
||||
"/wd4244",
|
||||
@@ -51,6 +31,7 @@ cc_library(
|
||||
}),
|
||||
includes = ["src/main/native/thirdparty/apriltag/include/common"],
|
||||
strip_include_prefix = "src/main/native/thirdparty/apriltag/include",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
generate_resources(
|
||||
@@ -58,83 +39,29 @@ generate_resources(
|
||||
namespace = "frc",
|
||||
prefix = "APRILTAG",
|
||||
resource_files = glob(["src/main/native/resources/**"]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
wpilib_cc_library(
|
||||
name = "apriltag",
|
||||
cc_library(
|
||||
name = "apriltag.static",
|
||||
srcs = [":generate-resources"] + glob(
|
||||
["src/main/native/cpp/**"],
|
||||
exclude = ["src/main/native/cpp/jni/**"],
|
||||
),
|
||||
hdrs = glob(["src/main/native/include/**/*"]),
|
||||
extra_hdr_pkg_files = [":thirdparty-apriltag-src-pkg"],
|
||||
extra_src_pkg_files = [":apriltag-java-jni-hdrs-pkg"],
|
||||
local_defines = ["WPILIB_EXPORTS"],
|
||||
defines = ["WPILIB_EXPORTS"],
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":thirdparty-apriltag",
|
||||
"//wpimath",
|
||||
"//wpiutil",
|
||||
"//wpimath:wpimath.static",
|
||||
"//wpiutil:wpiutil.static",
|
||||
],
|
||||
)
|
||||
|
||||
wpilib_cc_shared_library(
|
||||
name = "shared/apriltag",
|
||||
auto_export_windows_symbols = False,
|
||||
dynamic_deps = [
|
||||
"//wpimath:shared/wpimath",
|
||||
"//wpiutil:shared/wpiutil",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":apriltag",
|
||||
":thirdparty-apriltag",
|
||||
],
|
||||
)
|
||||
|
||||
wpilib_cc_static_library(
|
||||
name = "static/apriltag",
|
||||
static_deps = [
|
||||
"//wpimath:static/wpimath",
|
||||
"//wpiutil:static/wpiutil",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":apriltag",
|
||||
],
|
||||
)
|
||||
|
||||
wpilib_jni_cc_library(
|
||||
name = "apriltagjni",
|
||||
srcs = glob(["src/main/native/cpp/jni/**"]),
|
||||
java_dep = ":apriltag-java",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":apriltag",
|
||||
],
|
||||
)
|
||||
|
||||
wpilib_cc_shared_library(
|
||||
name = "shared/apriltagjni",
|
||||
auto_export_windows_symbols = False,
|
||||
dynamic_deps = [
|
||||
":shared/apriltag",
|
||||
"//wpimath:shared/wpimath",
|
||||
"//wpiutil:shared/wpiutil",
|
||||
],
|
||||
use_debug_name = False,
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":apriltagjni"],
|
||||
)
|
||||
|
||||
wpilib_jni_java_library(
|
||||
java_library(
|
||||
name = "apriltag-java",
|
||||
srcs = glob(["src/main/java/**/*.java"]),
|
||||
extra_source_pkgs = ["resources"],
|
||||
maven_artifact_name = "apriltag-java",
|
||||
maven_group_id = "edu.wpi.first.apriltag",
|
||||
native_libs = [":apriltagjni"],
|
||||
resource_strip_prefix = "apriltag/src/main/native/resources",
|
||||
resources = glob(["src/main/native/resources/**"]),
|
||||
visibility = ["//visibility:public"],
|
||||
@@ -148,12 +75,6 @@ wpilib_jni_java_library(
|
||||
],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "resources",
|
||||
srcs = glob(["src/main/native/resources/**"]),
|
||||
strip_prefix = "src/main/native/resources/",
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "apriltag-cpp-test",
|
||||
size = "small",
|
||||
@@ -162,22 +83,8 @@ cc_test(
|
||||
"no-asan",
|
||||
],
|
||||
deps = [
|
||||
":apriltag",
|
||||
"//thirdparty/googletest",
|
||||
],
|
||||
)
|
||||
|
||||
wpilib_java_junit5_test(
|
||||
name = "apriltag-java-test",
|
||||
srcs = glob(["src/test/java/**/*.java"]),
|
||||
resource_strip_prefix = "apriltag/src/test/resources",
|
||||
resources = glob(["src/test/resources/**"]),
|
||||
deps = [
|
||||
":apriltag-java",
|
||||
"//wpimath:wpimath-java",
|
||||
"//wpiutil:wpiutil-java",
|
||||
"@bzlmodrio-opencv//libraries/java/opencv",
|
||||
"@maven//:com_fasterxml_jackson_core_jackson_databind",
|
||||
":apriltag.static",
|
||||
"//thirdparty/googletest:googletest.static",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -185,7 +92,7 @@ cc_binary(
|
||||
name = "DevMain-Cpp",
|
||||
srcs = ["src/dev/native/cpp/main.cpp"],
|
||||
deps = [
|
||||
":apriltag",
|
||||
":apriltag.static",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -201,14 +108,5 @@ java_binary(
|
||||
py_binary(
|
||||
name = "convert_apriltag_layouts",
|
||||
srcs = ["convert_apriltag_layouts.py"],
|
||||
target_compatible_with = select({
|
||||
"@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
)
|
||||
|
||||
package_minimal_jni_project(
|
||||
name = "apriltag",
|
||||
maven_artifact_name = "apriltag-cpp",
|
||||
maven_group_id = "edu.wpi.first.apriltag",
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
||||
@@ -17,13 +17,17 @@ public enum AprilTagFields {
|
||||
/** 2025 Reefscape Welded (see TU 12). */
|
||||
k2025ReefscapeWelded("2025-reefscape-welded.json"),
|
||||
/** 2025 Reefscape AndyMark (see TU 12). */
|
||||
k2025ReefscapeAndyMark("2025-reefscape-andymark.json");
|
||||
k2025ReefscapeAndyMark("2025-reefscape-andymark.json"),
|
||||
/** 2026 Rebuilt Welded. */
|
||||
k2026RebuiltWelded("2026-rebuilt-welded.json"),
|
||||
/** 2026 Rebuilt AndyMark. */
|
||||
k2026RebuiltAndymark("2026-rebuilt-andymark.json");
|
||||
|
||||
/** Base resource directory. */
|
||||
public static final String kBaseResourceDir = "/edu/wpi/first/apriltag/";
|
||||
|
||||
/** Alias to the current game. */
|
||||
public static final AprilTagFields kDefaultField = k2025ReefscapeWelded;
|
||||
public static final AprilTagFields kDefaultField = k2026RebuiltWelded;
|
||||
|
||||
/** Resource filename. */
|
||||
public final String m_resourceFile;
|
||||
|
||||
@@ -135,6 +135,8 @@ std::string_view GetResource_2023_chargedup_json();
|
||||
std::string_view GetResource_2024_crescendo_json();
|
||||
std::string_view GetResource_2025_reefscape_welded_json();
|
||||
std::string_view GetResource_2025_reefscape_andymark_json();
|
||||
std::string_view GetResource_2026_rebuilt_welded_json();
|
||||
std::string_view GetResource_2026_rebuilt_andymark_json();
|
||||
|
||||
} // namespace frc
|
||||
|
||||
@@ -156,6 +158,12 @@ AprilTagFieldLayout AprilTagFieldLayout::LoadField(AprilTagField field) {
|
||||
case AprilTagField::k2025ReefscapeAndyMark:
|
||||
fieldString = GetResource_2025_reefscape_andymark_json();
|
||||
break;
|
||||
case AprilTagField::k2026RebuiltWelded:
|
||||
fieldString = GetResource_2026_rebuilt_welded_json();
|
||||
break;
|
||||
case AprilTagField::k2026RebuiltAndyMark:
|
||||
fieldString = GetResource_2026_rebuilt_andymark_json();
|
||||
break;
|
||||
case AprilTagField::kNumFields:
|
||||
throw std::invalid_argument("Invalid Field");
|
||||
}
|
||||
|
||||
@@ -24,8 +24,12 @@ enum class AprilTagField {
|
||||
k2025ReefscapeAndyMark,
|
||||
/// 2025 Reefscape Welded (see TU12).
|
||||
k2025ReefscapeWelded,
|
||||
/// 2026 Rebuilt Andymark.
|
||||
k2026RebuiltAndyMark,
|
||||
/// 2026 Rebuilt Welded.
|
||||
k2026RebuiltWelded,
|
||||
/// Alias to the current game.
|
||||
kDefaultField = k2025ReefscapeWelded,
|
||||
kDefaultField = k2026RebuiltWelded,
|
||||
|
||||
// This is a placeholder for denoting the last supported field. This should
|
||||
// always be the last entry in the enum and should not be used by users
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
ID,X,Y,Z,Z-Rotation,X-Rotation
|
||||
1,467.085,291.791,35,180,0
|
||||
2,468.559,182.077,44.25,90,0
|
||||
3,444.797,172.321,44.25,180,0
|
||||
4,444.797,158.321,44.25,180,0
|
||||
5,468.559,134.565,44.25,270,0
|
||||
6,467.085,24.851,35,180,0
|
||||
7,470.034,24.851,35,0,0
|
||||
8,482.559,134.565,44.25,270,0
|
||||
9,492.329,144.321,44.25,0,0
|
||||
10,492.329,158.321,44.25,0,0
|
||||
11,482.559,182.077,44.25,90,0
|
||||
12,470.034,291.791,35,0,0
|
||||
13,649.58,291.02,21.75,180,0
|
||||
14,649.58,274.02,21.75,180,0
|
||||
15,649.566,169.783,21.75,180,0
|
||||
16,649.566,152.783,21.75,180,0
|
||||
17,183.034,24.851,35,0,0
|
||||
18,181.559,134.565,44.25,270,0
|
||||
19,205.321,144.321,44.25,0,0
|
||||
20,205.321,158.321,44.25,0,0
|
||||
21,181.559,182.077,44.25,90,0
|
||||
22,183.034,291.791,35,0,0
|
||||
23,180.085,291.791,35,180,0
|
||||
24,167.559,182.077,44.25,90,0
|
||||
25,157.79,172.321,44.25,180,0
|
||||
26,157.79,158.321,44.25,180,0
|
||||
27,167.559,134.565,44.25,270,0
|
||||
28,180.085,24.851,35,180,0
|
||||
29,0.539,25.621,21.75,0,0
|
||||
30,0.539,42.621,21.75,0,0
|
||||
31,0.553,146.858,21.75,0,0
|
||||
32,0.553,163.858,21.75,0,0
|
||||
|
@@ -0,0 +1,584 @@
|
||||
{
|
||||
"tags": [
|
||||
{
|
||||
"ID": 1,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.863959,
|
||||
"y": 7.411491399999999,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 2,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.9013986,
|
||||
"y": 4.6247558,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.7071067811865476,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 3,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.2978438,
|
||||
"y": 4.3769534,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 4,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.2978438,
|
||||
"y": 4.0213534,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 5,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.9013986,
|
||||
"y": 3.417951,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 6,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.863959,
|
||||
"y": 0.6312154,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 7,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.9388636,
|
||||
"y": 0.6312154,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 8,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.2569986,
|
||||
"y": 3.417951,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 9,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.5051566,
|
||||
"y": 3.6657534,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 10,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.5051566,
|
||||
"y": 4.0213534,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 11,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.2569986,
|
||||
"y": 4.6247558,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.7071067811865476,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 12,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.9388636,
|
||||
"y": 7.411491399999999,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 13,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.499332,
|
||||
"y": 7.391907999999999,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 14,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.499332,
|
||||
"y": 6.960107999999999,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 15,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.4989764,
|
||||
"y": 4.3124882,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 16,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.4989764,
|
||||
"y": 3.8806881999999994,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 17,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.6490636,
|
||||
"y": 0.6312154,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 18,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.6115986,
|
||||
"y": 3.417951,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 19,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 5.2151534,
|
||||
"y": 3.6657534,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 20,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 5.2151534,
|
||||
"y": 4.0213534,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 21,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.6115986,
|
||||
"y": 4.6247558,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.7071067811865476,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 22,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.6490636,
|
||||
"y": 7.411491399999999,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 23,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.574159,
|
||||
"y": 7.411491399999999,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 24,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.2559986,
|
||||
"y": 4.6247558,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.7071067811865476,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 25,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.007866,
|
||||
"y": 4.3769534,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 26,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.007866,
|
||||
"y": 4.0213534,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 27,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.2559986,
|
||||
"y": 3.417951,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 28,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.574159,
|
||||
"y": 0.6312154,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 29,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.0136906,
|
||||
"y": 0.6507734,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 30,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.0136906,
|
||||
"y": 1.0825734,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 31,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.0140462,
|
||||
"y": 3.7301932,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 32,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.0140462,
|
||||
"y": 4.1619931999999995,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"field": {
|
||||
"length": 16.518,
|
||||
"width": 8.043
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
ID,X,Y,Z,Z-Rotation,X-Rotation
|
||||
1,467.637,292.314,35,180,0
|
||||
2,469.111,182.6,44.25,90,0
|
||||
3,445.349,172.844,44.25,180,0
|
||||
4,445.349,158.844,44.25,180,0
|
||||
5,469.111,135.088,44.25,270,0
|
||||
6,467.637,25.374,35,180,0
|
||||
7,470.586,25.374,35,0,0
|
||||
8,483.111,135.088,44.25,270,0
|
||||
9,492.881,144.844,44.25,0,0
|
||||
10,492.881,158.844,44.25,0,0
|
||||
11,483.111,182.6,44.25,90,0
|
||||
12,470.586,292.314,35,0,0
|
||||
13,650.918,291.469,21.75,180,0
|
||||
14,650.918,274.469,21.75,180,0
|
||||
15,650.904,170.219,21.75,180,0
|
||||
16,650.904,153.219,21.75,180,0
|
||||
17,183.586,25.374,35,0,0
|
||||
18,182.111,135.088,44.25,270,0
|
||||
19,205.873,144.844,44.25,0,0
|
||||
20,205.873,158.844,44.25,0,0
|
||||
21,182.111,182.6,44.25,90,0
|
||||
22,183.586,292.314,35,0,0
|
||||
23,180.637,292.314,35,180,0
|
||||
24,168.111,182.6,44.25,90,0
|
||||
25,158.341,172.844,44.25,180,0
|
||||
26,158.341,158.844,44.25,180,0
|
||||
27,168.111,135.088,44.25,270,0
|
||||
28,180.637,25.374,35,180,0
|
||||
29,0.305,26.219,21.75,0,0
|
||||
30,0.305,43.219,21.75,0,0
|
||||
31,0.318,147.469,21.75,0,0
|
||||
32,0.318,164.469,21.75,0,0
|
||||
|
@@ -0,0 +1,584 @@
|
||||
{
|
||||
"tags": [
|
||||
{
|
||||
"ID": 1,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.8779798,
|
||||
"y": 7.4247756,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 2,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.9154194,
|
||||
"y": 4.638039999999999,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.7071067811865476,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 3,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.3118646,
|
||||
"y": 4.3902376,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 4,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.3118646,
|
||||
"y": 4.0346376,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 5,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.9154194,
|
||||
"y": 3.4312351999999997,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 6,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.8779798,
|
||||
"y": 0.6444996,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 7,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.9528844,
|
||||
"y": 0.6444996,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 8,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.2710194,
|
||||
"y": 3.4312351999999997,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 9,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.519177399999998,
|
||||
"y": 3.6790375999999996,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 10,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.519177399999998,
|
||||
"y": 4.0346376,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 11,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 12.2710194,
|
||||
"y": 4.638039999999999,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.7071067811865476,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 12,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.9528844,
|
||||
"y": 7.4247756,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 13,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.5333172,
|
||||
"y": 7.4033126,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 14,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.5333172,
|
||||
"y": 6.9715126,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 15,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.5329616,
|
||||
"y": 4.3235626,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 16,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.5329616,
|
||||
"y": 3.8917626,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 17,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.6630844,
|
||||
"y": 0.6444996,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 18,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.6256194,
|
||||
"y": 3.4312351999999997,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 19,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 5.229174199999999,
|
||||
"y": 3.6790375999999996,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 20,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 5.229174199999999,
|
||||
"y": 4.0346376,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 21,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.6256194,
|
||||
"y": 4.638039999999999,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.7071067811865476,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 22,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.6630844,
|
||||
"y": 7.4247756,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 23,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.5881798,
|
||||
"y": 7.4247756,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 24,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.2700194,
|
||||
"y": 4.638039999999999,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.7071067811865476,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 25,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.0218614,
|
||||
"y": 4.3902376,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 26,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.0218614,
|
||||
"y": 4.0346376,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 27,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.2700194,
|
||||
"y": 3.4312351999999997,
|
||||
"z": 1.12395
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 28,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.5881798,
|
||||
"y": 0.6444996,
|
||||
"z": 0.889
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 29,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.0077469999999999995,
|
||||
"y": 0.6659626,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 30,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.0077469999999999995,
|
||||
"y": 1.0977626,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 31,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.0080772,
|
||||
"y": 3.7457125999999996,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 32,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.0080772,
|
||||
"y": 4.1775126,
|
||||
"z": 0.55245
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"field": {
|
||||
"length": 16.541,
|
||||
"width": 8.069
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
robotpy-apriltag
|
||||
================
|
||||
|
||||
RobotPy wrappers around WPILib's version of the apriltag library.
|
||||
@@ -1,41 +0,0 @@
|
||||
[build-system]
|
||||
build-backend = "hatchling.build"
|
||||
requires = [
|
||||
"hatchling",
|
||||
"hatch-nativelib~=0.2.0",
|
||||
"hatch-robotpy~=0.2.1",
|
||||
"robotpy-native-wpiutil==2027.0.0a2",
|
||||
"robotpy-native-wpimath==2027.0.0a2",
|
||||
]
|
||||
|
||||
[project]
|
||||
name = "robotpy-native-apriltag"
|
||||
version = "2027.0.0a2"
|
||||
description = "WPILib AprilTag Library"
|
||||
license = "BSD-3-Clause"
|
||||
|
||||
dependencies = [
|
||||
"robotpy-native-wpiutil==2027.0.0a2",
|
||||
"robotpy-native-wpimath==2027.0.0a2",
|
||||
]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/native"]
|
||||
|
||||
[[tool.hatch.build.hooks.robotpy.maven_lib_download]]
|
||||
artifact_id = "apriltag-cpp"
|
||||
group_id = "edu.wpi.first.apriltag"
|
||||
repo_url = "https://frcmaven.wpi.edu/artifactory/release-2027"
|
||||
version = "2027.0.0-alpha-2"
|
||||
|
||||
extract_to = "src/native/apriltag"
|
||||
libs = ["apriltag"]
|
||||
|
||||
[[tool.hatch.build.hooks.nativelib.pcfile]]
|
||||
pcfile = "src/native/apriltag/robotpy-native-apriltag.pc"
|
||||
name = "apriltag"
|
||||
|
||||
includedir = "src/native/apriltag/include"
|
||||
libdir = "src/native/apriltag/lib"
|
||||
shared_libraries = ["apriltag"]
|
||||
requires = ["robotpy-native-wpiutil", "robotpy-native-wpimath"]
|
||||
@@ -1,74 +0,0 @@
|
||||
[build-system]
|
||||
build-backend = "hatchling.build"
|
||||
requires = [
|
||||
"semiwrap~=0.1.7",
|
||||
"hatch-meson~=0.1.0b2",
|
||||
"hatch-robotpy~=0.2.1",
|
||||
"hatchling",
|
||||
"robotpy-native-apriltag==2027.0.0a2",
|
||||
"robotpy-wpiutil==2027.0.0a2",
|
||||
"robotpy-wpimath==2027.0.0a2",
|
||||
]
|
||||
|
||||
[project]
|
||||
name = "robotpy-apriltag"
|
||||
version = "2027.0.0a2"
|
||||
description = "RobotPy bindings for WPILib's AprilTag library"
|
||||
authors = [
|
||||
{name = "RobotPy Development Team", email = "robotpy@googlegroups.com"},
|
||||
]
|
||||
license = "BSD-3-Clause"
|
||||
dependencies = [
|
||||
"robotpy-native-apriltag==2027.0.0a2",
|
||||
"robotpy-wpiutil==2027.0.0a2",
|
||||
"robotpy-wpimath==2027.0.0a2",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
"Source code" = "https://github.com/robotpy/mostrobotpy"
|
||||
|
||||
|
||||
[tool.hatch.build.hooks.robotpy]
|
||||
version_file = "robotpy_apriltag/version.py"
|
||||
|
||||
[tool.hatch.build.hooks.semiwrap]
|
||||
|
||||
[tool.hatch.build.hooks.meson]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["robotpy_apriltag"]
|
||||
|
||||
|
||||
[tool.semiwrap]
|
||||
update_init = [
|
||||
"robotpy_apriltag robotpy_apriltag._apriltag"
|
||||
]
|
||||
scan_headers_ignore = [
|
||||
"common/*",
|
||||
"test/*",
|
||||
|
||||
"apriltag.h",
|
||||
"apriltag_math.h",
|
||||
"apriltag_pose.h",
|
||||
|
||||
"frc/apriltag/AprilTagDetector_cv.h",
|
||||
|
||||
"tag16h5.h",
|
||||
"tag36h11.h",
|
||||
]
|
||||
|
||||
[tool.semiwrap.extension_modules."robotpy_apriltag._apriltag"]
|
||||
name = "apriltag"
|
||||
wraps = ["robotpy-native-apriltag"]
|
||||
depends = ["wpiutil", "wpimath"]
|
||||
|
||||
[tool.semiwrap.extension_modules."robotpy_apriltag._apriltag".headers]
|
||||
# frc/apriltag
|
||||
AprilTag = "frc/apriltag/AprilTag.h"
|
||||
AprilTagDetection = "frc/apriltag/AprilTagDetection.h"
|
||||
AprilTagDetector = "frc/apriltag/AprilTagDetector.h"
|
||||
# AprilTagDetector_cv = "frc/apriltag/AprilTagDetector_cv.h"
|
||||
AprilTagFieldLayout = "frc/apriltag/AprilTagFieldLayout.h"
|
||||
AprilTagFields = "frc/apriltag/AprilTagFields.h"
|
||||
AprilTagPoseEstimate = "frc/apriltag/AprilTagPoseEstimate.h"
|
||||
AprilTagPoseEstimator = "frc/apriltag/AprilTagPoseEstimator.h"
|
||||
@@ -1,22 +0,0 @@
|
||||
from . import _init__apriltag
|
||||
|
||||
# autogenerated by 'semiwrap create-imports robotpy_apriltag robotpy_apriltag._apriltag'
|
||||
from ._apriltag import (
|
||||
AprilTag,
|
||||
AprilTagDetection,
|
||||
AprilTagDetector,
|
||||
AprilTagField,
|
||||
AprilTagFieldLayout,
|
||||
AprilTagPoseEstimate,
|
||||
AprilTagPoseEstimator,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"AprilTag",
|
||||
"AprilTagDetection",
|
||||
"AprilTagDetector",
|
||||
"AprilTagField",
|
||||
"AprilTagFieldLayout",
|
||||
"AprilTagPoseEstimate",
|
||||
"AprilTagPoseEstimator",
|
||||
]
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
#include "semiwrap_init.robotpy_apriltag._apriltag.hpp"
|
||||
|
||||
SEMIWRAP_PYBIND11_MODULE(m) { initWrapper(m); }
|
||||
@@ -1,16 +0,0 @@
|
||||
functions:
|
||||
to_json:
|
||||
ignore: true
|
||||
from_json:
|
||||
ignore: true
|
||||
classes:
|
||||
frc::AprilTag:
|
||||
attributes:
|
||||
ID:
|
||||
pose:
|
||||
methods:
|
||||
Generate36h11AprilTagImage:
|
||||
ignore: true
|
||||
Generate16h5AprilTagImage:
|
||||
ignore: true
|
||||
operator==:
|
||||
@@ -1,43 +0,0 @@
|
||||
extra_includes:
|
||||
- pybind11/eigen.h
|
||||
|
||||
classes:
|
||||
frc::AprilTagDetection:
|
||||
methods:
|
||||
GetFamily:
|
||||
GetId:
|
||||
GetHamming:
|
||||
GetDecisionMargin:
|
||||
GetHomography:
|
||||
GetHomographyMatrix:
|
||||
GetCenter:
|
||||
GetCorner:
|
||||
GetCorners:
|
||||
inline_code: |
|
||||
.def("__repr__", [](const AprilTagDetection &self) {
|
||||
return py::str("<AprilTagDetection tag_family={} tag_id={} hamming={} decision_margin={} center={}>")
|
||||
.format(self.GetFamily(), self.GetId(), self.GetHamming(), self.GetDecisionMargin(), self.GetCenter());
|
||||
})
|
||||
frc::AprilTagDetection::Point:
|
||||
attributes:
|
||||
x:
|
||||
y:
|
||||
inline_code: |
|
||||
.def(py::init([](double x, double y) {
|
||||
AprilTagDetection::Point pt{x, y};
|
||||
return std::make_unique<AprilTagDetection::Point>(std::move(pt));
|
||||
}), py::arg("x"), py::arg("y"))
|
||||
.def("__len__", [](const AprilTagDetection::Point &self) { return 2; })
|
||||
.def("__getitem__", [](const AprilTagDetection::Point &self, int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return self.x;
|
||||
case 1:
|
||||
return self.y;
|
||||
default:
|
||||
throw std::out_of_range("AprilTagDetection.Point index out of range");
|
||||
}
|
||||
})
|
||||
.def("__repr__", [](const AprilTagDetection::Point &self) {
|
||||
return py::str("AprilTagDetection.Point(x={}, y={})").format(self.x, self.y);
|
||||
})
|
||||
@@ -1,99 +0,0 @@
|
||||
extra_includes:
|
||||
- pybind11_typing.h
|
||||
|
||||
classes:
|
||||
frc::AprilTagDetector:
|
||||
methods:
|
||||
AprilTagDetector:
|
||||
SetConfig:
|
||||
GetConfig:
|
||||
SetQuadThresholdParameters:
|
||||
GetQuadThresholdParameters:
|
||||
AddFamily:
|
||||
RemoveFamily:
|
||||
ClearFamilies:
|
||||
Detect:
|
||||
overloads:
|
||||
int, int, int, uint8_t*:
|
||||
ignore: true
|
||||
int, int, uint8_t*:
|
||||
ignore: true
|
||||
inline_code: |
|
||||
.def("detect", [](AprilTagDetector *self, py::buffer img) {
|
||||
|
||||
// validate the input image buffer
|
||||
auto buf = img.request();
|
||||
if (buf.ndim != 2) {
|
||||
throw py::value_error("buffer must only have two dimensions");
|
||||
} else if (buf.itemsize != 1) {
|
||||
throw py::value_error("buffer elements must be bytes");
|
||||
}
|
||||
|
||||
// We are going to move the detection result into this shared_ptr
|
||||
// so that python can keep it alive. We don't expose the result directly
|
||||
// to the user because we'd have to pretend it's a list, and that would
|
||||
// be annoying.
|
||||
std::shared_ptr<AprilTagDetector::Results> c_result;
|
||||
{
|
||||
py::gil_scoped_release unlock;
|
||||
c_result = std::make_shared<AprilTagDetector::Results>(std::move(self->Detect(buf.shape[1], buf.shape[0], (uint8_t*)buf.ptr)));
|
||||
}
|
||||
|
||||
// This tells python about the shared_ptr, and it'll keep it alive as
|
||||
// long as the python reference is alive. When we call get(), we marked
|
||||
// the return value as reference_internal so python will keep the python
|
||||
// reference for the results object alive for as long as all of its
|
||||
// results that we put into the list are alive
|
||||
py::object py_result = py::cast(c_result);
|
||||
auto len = c_result->size();
|
||||
auto get = py_result.attr("get");
|
||||
py::typing::List<AprilTagDetection> l(len);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
l[i] = get(i);
|
||||
}
|
||||
return l;
|
||||
}, py::arg("image"),
|
||||
R"doc(
|
||||
Detect tags from an 8-bit grayscale image with shape (height, width)
|
||||
|
||||
:return: list of results
|
||||
)doc"
|
||||
)
|
||||
frc::AprilTagDetector::Config:
|
||||
attributes:
|
||||
numThreads:
|
||||
quadDecimate:
|
||||
quadSigma:
|
||||
refineEdges:
|
||||
decodeSharpening:
|
||||
debug:
|
||||
methods:
|
||||
operator==:
|
||||
frc::AprilTagDetector::QuadThresholdParameters:
|
||||
attributes:
|
||||
minClusterPixels:
|
||||
maxNumMaxima:
|
||||
criticalAngle:
|
||||
maxLineFitMSE:
|
||||
minWhiteBlackDiff:
|
||||
deglitch:
|
||||
methods:
|
||||
operator==:
|
||||
frc::AprilTagDetector::Results:
|
||||
rename: _Results
|
||||
ignored_bases:
|
||||
- std::span<const AprilTagDetection* const>
|
||||
force_no_trampoline: true
|
||||
methods:
|
||||
Results:
|
||||
overloads:
|
||||
'':
|
||||
ignore: true
|
||||
void*, const private_init&:
|
||||
ignore: true
|
||||
inline_code: |
|
||||
// use the keepalive to keep the array of results around until
|
||||
// the user deletes them
|
||||
.def("get", [](const AprilTagDetector::Results &self, int i) {
|
||||
return self[i];
|
||||
}, py::return_value_policy::reference_internal)
|
||||
@@ -1,29 +0,0 @@
|
||||
functions:
|
||||
to_json:
|
||||
ignore: true
|
||||
from_json:
|
||||
ignore: true
|
||||
LoadAprilTagLayoutField:
|
||||
ignore: true
|
||||
classes:
|
||||
frc::AprilTagFieldLayout:
|
||||
enums:
|
||||
OriginPosition:
|
||||
methods:
|
||||
AprilTagFieldLayout:
|
||||
overloads:
|
||||
'':
|
||||
std::string_view:
|
||||
std::vector<AprilTag>, units::meter_t, units::meter_t:
|
||||
LoadField:
|
||||
GetFieldLength:
|
||||
GetFieldWidth:
|
||||
GetTags:
|
||||
SetOrigin:
|
||||
overloads:
|
||||
OriginPosition:
|
||||
const Pose3d&:
|
||||
GetOrigin:
|
||||
GetTagPose:
|
||||
Serialize:
|
||||
operator==:
|
||||
@@ -1,2 +0,0 @@
|
||||
enums:
|
||||
AprilTagField:
|
||||
@@ -1,9 +0,0 @@
|
||||
classes:
|
||||
frc::AprilTagPoseEstimate:
|
||||
attributes:
|
||||
pose1:
|
||||
pose2:
|
||||
error1:
|
||||
error2:
|
||||
methods:
|
||||
GetAmbiguity:
|
||||
@@ -1,36 +0,0 @@
|
||||
extra_includes:
|
||||
- frc/apriltag/AprilTagDetection.h
|
||||
|
||||
classes:
|
||||
frc::AprilTagPoseEstimator:
|
||||
methods:
|
||||
AprilTagPoseEstimator:
|
||||
SetConfig:
|
||||
GetConfig:
|
||||
EstimateHomography:
|
||||
overloads:
|
||||
const AprilTagDetection& [const]:
|
||||
std::span<const double, 9> [const]:
|
||||
EstimateOrthogonalIteration:
|
||||
overloads:
|
||||
const AprilTagDetection&, int [const]:
|
||||
std::span<const double, 9>, std::span<const double, 8>, int [const]:
|
||||
Estimate:
|
||||
overloads:
|
||||
const AprilTagDetection& [const]:
|
||||
std::span<const double, 9>, std::span<const double, 8> [const]:
|
||||
frc::AprilTagPoseEstimator::Config:
|
||||
force_no_default_constructor: true
|
||||
attributes:
|
||||
tagSize:
|
||||
fx:
|
||||
fy:
|
||||
cx:
|
||||
cy:
|
||||
methods:
|
||||
operator==:
|
||||
inline_code: |
|
||||
.def(py::init([](units::meter_t tagSize, double fx, double fy, double cx, double cy) {
|
||||
AprilTagPoseEstimator::Config cfg{tagSize, fx, fy, cx, cy};
|
||||
return std::make_unique<AprilTagPoseEstimator::Config>(std::move(cfg));
|
||||
}), py::arg("tagSize"), py::arg("fx"), py::arg("fy"), py::arg("cx"), py::arg("cy"))
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,119 +0,0 @@
|
||||
import cv2
|
||||
import robotpy_apriltag
|
||||
from wpimath.geometry import Transform3d
|
||||
|
||||
import math
|
||||
import pathlib
|
||||
import pytest
|
||||
|
||||
|
||||
def test_point():
|
||||
point = robotpy_apriltag.AprilTagDetection.Point()
|
||||
|
||||
x, y = point
|
||||
|
||||
assert x == 0
|
||||
assert y == 0
|
||||
|
||||
|
||||
def _load_grayscale_image(fname):
|
||||
full_path = pathlib.Path(__file__).parent / fname
|
||||
img = cv2.imread(str(full_path))
|
||||
return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||
|
||||
|
||||
def test_1():
|
||||
detector = robotpy_apriltag.AprilTagDetector()
|
||||
assert detector.addFamily("tag16h5")
|
||||
assert detector.addFamily("tag36h11")
|
||||
|
||||
img = _load_grayscale_image("tag1_640_480.jpg")
|
||||
results = detector.detect(img)
|
||||
|
||||
assert len(results) == 1
|
||||
assert results[0].getFamily() == "tag36h11"
|
||||
assert results[0].getId() == 1
|
||||
assert results[0].getHamming() == 0
|
||||
|
||||
estimator = robotpy_apriltag.AprilTagPoseEstimator(
|
||||
robotpy_apriltag.AprilTagPoseEstimator.Config(0.2, 500, 500, 320, 240)
|
||||
)
|
||||
|
||||
est = estimator.estimateOrthogonalIteration(results[0], 50)
|
||||
assert est.pose2 == Transform3d()
|
||||
pose = estimator.estimate(results[0])
|
||||
assert est.pose1 == pose
|
||||
|
||||
|
||||
def test_pose_rotated_x():
|
||||
"""
|
||||
This tag is rotated such that the top is closer to the camera than the bottom. In the camera
|
||||
frame, with +x to the right, this is a rotation about +X by 45 degrees.
|
||||
"""
|
||||
|
||||
detector = robotpy_apriltag.AprilTagDetector()
|
||||
assert detector.addFamily("tag16h5")
|
||||
|
||||
img = _load_grayscale_image("tag2_45deg_X.png")
|
||||
results = detector.detect(img)
|
||||
|
||||
assert len(results) == 1
|
||||
|
||||
estimator = robotpy_apriltag.AprilTagPoseEstimator(
|
||||
robotpy_apriltag.AprilTagPoseEstimator.Config(
|
||||
0.2, 500, 500, img.shape[1] / 2.0, img.shape[0] / 2.0
|
||||
)
|
||||
)
|
||||
est = estimator.estimateOrthogonalIteration(results[0], 50)
|
||||
assert pytest.approx(est.pose1.rotation().x, abs=0.1) == math.radians(45)
|
||||
assert pytest.approx(est.pose1.rotation().y, abs=0.1) == math.radians(0)
|
||||
assert pytest.approx(est.pose1.rotation().z, abs=0.1) == math.radians(0)
|
||||
|
||||
|
||||
def test_pose_rotated_y():
|
||||
"""
|
||||
This tag is rotated such that the right is closer to the camera than the left. In the camera
|
||||
frame, with +y down, this is a rotation of 45 degrees about +y.
|
||||
"""
|
||||
|
||||
detector = robotpy_apriltag.AprilTagDetector()
|
||||
assert detector.addFamily("tag16h5")
|
||||
|
||||
img = _load_grayscale_image("tag2_45deg_y.png")
|
||||
results = detector.detect(img)
|
||||
|
||||
assert len(results) == 1
|
||||
|
||||
estimator = robotpy_apriltag.AprilTagPoseEstimator(
|
||||
robotpy_apriltag.AprilTagPoseEstimator.Config(
|
||||
0.2, 500, 500, img.shape[1] / 2.0, img.shape[0] / 2.0
|
||||
)
|
||||
)
|
||||
est = estimator.estimateOrthogonalIteration(results[0], 50)
|
||||
assert pytest.approx(est.pose1.rotation().x, abs=0.1) == math.radians(0)
|
||||
assert pytest.approx(est.pose1.rotation().y, abs=0.1) == math.radians(45)
|
||||
assert pytest.approx(est.pose1.rotation().z, abs=0.1) == math.radians(0)
|
||||
|
||||
|
||||
def test_pose_straight_on():
|
||||
"""
|
||||
This tag is facing right at the camera -- no rotation should be observed.
|
||||
"""
|
||||
|
||||
detector = robotpy_apriltag.AprilTagDetector()
|
||||
assert detector.addFamily("tag16h5")
|
||||
|
||||
img = _load_grayscale_image("tag2_16h5_straight.png")
|
||||
results = detector.detect(img)
|
||||
|
||||
assert len(results) == 1
|
||||
|
||||
estimator = robotpy_apriltag.AprilTagPoseEstimator(
|
||||
robotpy_apriltag.AprilTagPoseEstimator.Config(
|
||||
0.2, 500, 500, img.shape[1] / 2.0, img.shape[0] / 2.0
|
||||
)
|
||||
)
|
||||
est = estimator.estimateOrthogonalIteration(results[0], 50)
|
||||
assert pytest.approx(est.pose1.rotation().x, abs=0.1) == math.radians(0)
|
||||
assert pytest.approx(est.pose1.rotation().y, abs=0.1) == math.radians(0)
|
||||
assert pytest.approx(est.pose1.rotation().z, abs=0.1) == math.radians(0)
|
||||
92
azure-pipelines-testbench.yaml
Normal file
92
azure-pipelines-testbench.yaml
Normal file
@@ -0,0 +1,92 @@
|
||||
# Testing steps for real hardware
|
||||
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
|
||||
stages:
|
||||
- stage: Build
|
||||
jobs:
|
||||
- job: IntegrationTests
|
||||
displayName: Integration Tests
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
container:
|
||||
image: wpilib/roborio-cross-ubuntu:2023-22.04
|
||||
|
||||
timeoutInMinutes: 0
|
||||
|
||||
steps:
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
|
||||
inputs:
|
||||
workingDirectory: ""
|
||||
gradleWrapperFile: "gradlew"
|
||||
gradleOptions: "-Xmx3072m"
|
||||
publishJUnitResults: false
|
||||
testResultsFiles: "**/TEST-*.xml"
|
||||
tasks: "copyWpilibJIntegrationTestJarToOutput copyWpilibCTestLibrariesToOutput"
|
||||
options: "-Ponlylinuxathena -PbuildServer -PskipJavaFormat"
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: "Integration Tests"
|
||||
targetPath: "build/integrationTestFiles"
|
||||
|
||||
- stage: TestBench
|
||||
displayName: Test Bench
|
||||
condition: false
|
||||
jobs:
|
||||
- job: Cpp
|
||||
displayName: C++
|
||||
pool: RoboRioConnections
|
||||
timeoutInMinutes: 30
|
||||
workspace:
|
||||
clean: all
|
||||
steps:
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: "Integration Tests"
|
||||
targetPath: "build/integrationTestFiles"
|
||||
|
||||
- task: ShellScript@2
|
||||
displayName: Run C++ Tests
|
||||
inputs:
|
||||
scriptPath: test-scripts/deploy-and-run-test-on-robot.sh
|
||||
args: 'cpp -A "--gtest_output=xml:/home/admin/testResults/cppreport.xml"'
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish C++ Test Results
|
||||
inputs:
|
||||
testResultsFormat: "JUnit"
|
||||
testResultsFiles: "*.xml"
|
||||
testRunTitle: "C++ Test Report"
|
||||
searchFolder: "$(System.DefaultWorkingDirectory)/test-reports"
|
||||
|
||||
- job: Java
|
||||
pool: RoboRioConnections
|
||||
timeoutInMinutes: 30
|
||||
workspace:
|
||||
clean: all
|
||||
steps:
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: "Integration Tests"
|
||||
targetPath: "build/integrationTestFiles"
|
||||
|
||||
- task: ShellScript@2
|
||||
displayName: Run Java Tests
|
||||
inputs:
|
||||
scriptPath: test-scripts/deploy-and-run-test-on-robot.sh
|
||||
args: "java"
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish Java Test Results
|
||||
inputs:
|
||||
testResultsFormat: "JUnit"
|
||||
testResultsFiles: "*.xml"
|
||||
testRunTitle: "Java Test Report"
|
||||
searchFolder: "$(System.DefaultWorkingDirectory)/test-reports"
|
||||
@@ -39,7 +39,7 @@ public class Main {
|
||||
private static final TravelingSalesman twistTraveler =
|
||||
new TravelingSalesman(
|
||||
(pose1, pose2) -> {
|
||||
var twist = pose2.minus(pose1).log();
|
||||
var twist = pose1.log(pose2);
|
||||
return Math.hypot(twist.dx, twist.dy);
|
||||
});
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ BENCHMARK(BM_Transform);
|
||||
|
||||
void BM_Twist(benchmark::State& state) {
|
||||
frc::TravelingSalesman traveler{[](auto pose1, auto pose2) {
|
||||
auto twist = (pose2 - pose1).Log();
|
||||
auto twist = pose1.Log(pose2);
|
||||
return units::math::hypot(twist.dx, twist.dy).value();
|
||||
}};
|
||||
// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
|
||||
|
||||
@@ -11,7 +11,7 @@ buildscript {
|
||||
plugins {
|
||||
id 'base'
|
||||
id 'edu.wpi.first.wpilib.versioning.WPILibVersioningPlugin' version '2023.0.1'
|
||||
id 'edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin' version '2025.0'
|
||||
id 'edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin' version '2020.2'
|
||||
id 'edu.wpi.first.NativeUtils' apply false
|
||||
id 'edu.wpi.first.GradleJni' version '1.2.0'
|
||||
id 'edu.wpi.first.GradleVsCode'
|
||||
@@ -32,7 +32,6 @@ allprojects {
|
||||
url = 'https://frcmaven.wpi.edu/artifactory/ex-mvn'
|
||||
}
|
||||
}
|
||||
wpilibRepositories.use2027Repos()
|
||||
if (project.hasProperty('releaseMode')) {
|
||||
wpilibRepositories.addAllReleaseRepositories(it)
|
||||
} else {
|
||||
@@ -111,8 +110,8 @@ subprojects {
|
||||
|
||||
plugins.withType(JavaPlugin) {
|
||||
java {
|
||||
sourceCompatibility = 21
|
||||
targetCompatibility = 21
|
||||
sourceCompatibility = 17
|
||||
targetCompatibility = 17
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
load("@bzlmodrio-opencv//libraries/cpp/opencv:libraries.bzl", "opencv_shared_libraries")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_test")
|
||||
load("@rules_java//java:defs.bzl", "java_binary")
|
||||
load("//shared/bazel/rules:cc_rules.bzl", "wpilib_cc_library", "wpilib_cc_shared_library", "wpilib_cc_static_library")
|
||||
load("//shared/bazel/rules:java_rules.bzl", "wpilib_java_library")
|
||||
load("//shared/bazel/rules:packaging.bzl", "package_minimal_cc_project")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
|
||||
load("@rules_java//java:defs.bzl", "java_binary", "java_library")
|
||||
|
||||
filegroup(
|
||||
name = "doxygen-files",
|
||||
srcs = glob([
|
||||
"src/main/native/include/**/*",
|
||||
]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
wpilib_cc_library(
|
||||
name = "cameraserver",
|
||||
cc_library(
|
||||
name = "cameraserver.static",
|
||||
srcs = glob(["src/main/native/cpp/**"]),
|
||||
hdrs = glob(["src/main/native/include/**/*"]),
|
||||
includes = [
|
||||
@@ -24,42 +12,19 @@ wpilib_cc_library(
|
||||
strip_include_prefix = "src/main/native/include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cscore",
|
||||
"//ntcore",
|
||||
"//cscore:cscore.static",
|
||||
"//ntcore:ntcore.static",
|
||||
],
|
||||
)
|
||||
|
||||
wpilib_cc_shared_library(
|
||||
name = "shared/cameraserver",
|
||||
dynamic_deps = [
|
||||
"//cscore:shared/cscore",
|
||||
"//ntcore:shared/ntcore",
|
||||
"//wpiutil:shared/wpiutil",
|
||||
] + opencv_shared_libraries,
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":cameraserver"],
|
||||
)
|
||||
|
||||
wpilib_cc_static_library(
|
||||
name = "static/cameraserver",
|
||||
static_deps = [
|
||||
"//cscore:static/cscore",
|
||||
"//ntcore:static/ntcore",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":cameraserver"],
|
||||
)
|
||||
|
||||
wpilib_java_library(
|
||||
java_library(
|
||||
name = "cameraserver-java",
|
||||
srcs = glob(["src/main/java/**/*.java"]),
|
||||
maven_artifact_name = "cameraserver-java",
|
||||
maven_group_id = "edu.wpi.first.cameraserver",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cscore:cscore-java",
|
||||
"//hal:hal-java",
|
||||
"//ntcore:ntcore-java",
|
||||
"//ntcore:networktables-java",
|
||||
"//wpimath:wpimath-java",
|
||||
"//wpinet:wpinet-java",
|
||||
"//wpiutil:wpiutil-java",
|
||||
@@ -72,8 +37,8 @@ cc_test(
|
||||
size = "small",
|
||||
srcs = glob(["src/test/native/**"]),
|
||||
deps = [
|
||||
":cameraserver",
|
||||
"//thirdparty/googletest",
|
||||
":cameraserver.static",
|
||||
"//thirdparty/googletest:googletest.static",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -81,7 +46,7 @@ cc_binary(
|
||||
name = "DevMain-Cpp",
|
||||
srcs = ["src/dev/native/cpp/main.cpp"],
|
||||
deps = [
|
||||
":cameraserver",
|
||||
":cameraserver.static",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -92,9 +57,3 @@ java_binary(
|
||||
deps = [
|
||||
],
|
||||
)
|
||||
|
||||
package_minimal_cc_project(
|
||||
name = "cameraserver",
|
||||
maven_artifact_name = "cameraserver-cpp",
|
||||
maven_group_id = "edu.wpi.first.cameraserver",
|
||||
)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
@FILENAME_DEP_REPLACE@
|
||||
@WPIUTIL_DEP_REPLACE@
|
||||
@DATALOG_DEP_REPLACE@
|
||||
@NTCORE_DEP_REPLACE@
|
||||
@CSCORE_DEP_REPLACE@
|
||||
find_dependency(OpenCV)
|
||||
|
||||
@@ -8,7 +8,7 @@ java_binary(
|
||||
"//cameraserver:cameraserver-java",
|
||||
"//cscore:cscore-java",
|
||||
"//hal:hal-java",
|
||||
"//ntcore:ntcore-java",
|
||||
"//ntcore:networktables-java",
|
||||
"//wpimath:wpimath-java",
|
||||
"//wpiutil:wpiutil-java",
|
||||
"@maven//:com_google_code_gson_gson",
|
||||
|
||||
@@ -61,6 +61,9 @@ model {
|
||||
lib project: ':cscore', library: 'cscore', linkage: 'static'
|
||||
lib project: ':wpinet', library: 'wpinet', linkage: 'static'
|
||||
lib project: ':wpiutil', library: 'wpiutil', linkage: 'static'
|
||||
if (binary.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
|
||||
nativeUtils.useRequiredLibrary(binary, 'ni_link_libraries', 'ni_runtime_libraries')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ public final class Main {
|
||||
} else {
|
||||
System.out.println("Setting up NetworkTables client for team " + team);
|
||||
ntinst.setServerTeam(team);
|
||||
ntinst.startClient("multicameraserver");
|
||||
ntinst.startClient4("multicameraserver");
|
||||
}
|
||||
|
||||
// start cameras
|
||||
|
||||
@@ -190,7 +190,7 @@ int main(int argc, char* argv[]) {
|
||||
ntinst.StartServer();
|
||||
} else {
|
||||
wpi::print("Setting up NetworkTables client for team {}\n", team);
|
||||
ntinst.StartClient("multicameraserver");
|
||||
ntinst.StartClient4("multicameraserver");
|
||||
ntinst.SetServerTeam(team);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
package edu.wpi.first.cameraserver;
|
||||
|
||||
import edu.wpi.first.cscore.AxisCamera;
|
||||
import edu.wpi.first.cscore.CameraServerJNI;
|
||||
import edu.wpi.first.cscore.CvSink;
|
||||
import edu.wpi.first.cscore.CvSource;
|
||||
@@ -540,7 +541,9 @@ public final class CameraServer {
|
||||
* @return The USB camera capturing images.
|
||||
*/
|
||||
public static UsbCamera startAutomaticCapture() {
|
||||
return startAutomaticCapture(m_defaultUsbDevice.getAndIncrement());
|
||||
UsbCamera camera = startAutomaticCapture(m_defaultUsbDevice.getAndIncrement());
|
||||
CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -555,7 +558,7 @@ public final class CameraServer {
|
||||
public static UsbCamera startAutomaticCapture(int dev) {
|
||||
UsbCamera camera = new UsbCamera("USB Camera " + dev, dev);
|
||||
startAutomaticCapture(camera);
|
||||
CameraServerSharedStore.reportUsage("UsbCamera[" + dev + "]", "auto");
|
||||
CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
@@ -569,7 +572,7 @@ public final class CameraServer {
|
||||
public static UsbCamera startAutomaticCapture(String name, int dev) {
|
||||
UsbCamera camera = new UsbCamera(name, dev);
|
||||
startAutomaticCapture(camera);
|
||||
CameraServerSharedStore.reportUsage("UsbCamera[" + dev + "]", "name");
|
||||
CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
@@ -583,7 +586,7 @@ public final class CameraServer {
|
||||
public static UsbCamera startAutomaticCapture(String name, String path) {
|
||||
UsbCamera camera = new UsbCamera(name, path);
|
||||
startAutomaticCapture(camera);
|
||||
CameraServerSharedStore.reportUsage("UsbCamera[" + path + "]", "path");
|
||||
CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
@@ -600,6 +603,72 @@ public final class CameraServer {
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* <p>This overload calls {@link #addAxisCamera(String, String)} with name "Axis Camera".
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @return The Axis camera capturing images.
|
||||
* @deprecated Call startAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2025")
|
||||
@SuppressWarnings("removal")
|
||||
public static AxisCamera addAxisCamera(String host) {
|
||||
return addAxisCamera("Axis Camera", host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* <p>This overload calls {@link #addAxisCamera(String, String[])} with name "Axis Camera".
|
||||
*
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @return The Axis camera capturing images.
|
||||
* @deprecated Call startAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2025")
|
||||
@SuppressWarnings("removal")
|
||||
public static AxisCamera addAxisCamera(String[] hosts) {
|
||||
return addAxisCamera("Axis Camera", hosts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @return The Axis camera capturing images.
|
||||
* @deprecated Call startAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2025")
|
||||
@SuppressWarnings("removal")
|
||||
public static AxisCamera addAxisCamera(String name, String host) {
|
||||
AxisCamera camera = new AxisCamera(name, host);
|
||||
// Create a passthrough MJPEG server for USB access
|
||||
startAutomaticCapture(camera);
|
||||
CameraServerSharedStore.getCameraServerShared().reportAxisCamera(camera.getHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @return The Axis camera capturing images.
|
||||
* @deprecated Call startAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2025")
|
||||
@SuppressWarnings("removal")
|
||||
public static AxisCamera addAxisCamera(String name, String[] hosts) {
|
||||
AxisCamera camera = new AxisCamera(name, hosts);
|
||||
// Create a passthrough MJPEG server for USB access
|
||||
startAutomaticCapture(camera);
|
||||
CameraServerSharedStore.getCameraServerShared().reportAxisCamera(camera.getHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a virtual camera for switching between two streams. Unlike the other addCamera methods,
|
||||
* this returns a VideoSink rather than a VideoSource. Calling setSource() on the returned object
|
||||
|
||||
@@ -21,12 +21,25 @@ public interface CameraServerShared {
|
||||
void reportDriverStationError(String error);
|
||||
|
||||
/**
|
||||
* Report usage.
|
||||
* Report an video server usage.
|
||||
*
|
||||
* @param resource the resource name
|
||||
* @param data arbitrary string data
|
||||
* @param id the usage id
|
||||
*/
|
||||
void reportUsage(String resource, String data);
|
||||
void reportVideoServer(int id);
|
||||
|
||||
/**
|
||||
* Report a usb camera usage.
|
||||
*
|
||||
* @param id the usage id
|
||||
*/
|
||||
void reportUsbCamera(int id);
|
||||
|
||||
/**
|
||||
* Report an axis camera usage.
|
||||
*
|
||||
* @param id the usage id
|
||||
*/
|
||||
void reportAxisCamera(int id);
|
||||
|
||||
/**
|
||||
* Get if running on a roboRIO.
|
||||
|
||||
@@ -20,11 +20,17 @@ public final class CameraServerSharedStore {
|
||||
cameraServerShared =
|
||||
new CameraServerShared() {
|
||||
@Override
|
||||
public void reportUsage(String resource, String data) {}
|
||||
public void reportVideoServer(int id) {}
|
||||
|
||||
@Override
|
||||
public void reportUsbCamera(int id) {}
|
||||
|
||||
@Override
|
||||
public void reportDriverStationError(String error) {}
|
||||
|
||||
@Override
|
||||
public void reportAxisCamera(int id) {}
|
||||
|
||||
@Override
|
||||
public Long getRobotMainThreadId() {
|
||||
return null;
|
||||
@@ -34,16 +40,6 @@ public final class CameraServerSharedStore {
|
||||
return cameraServerShared;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report usage.
|
||||
*
|
||||
* @param resource the resource name
|
||||
* @param data arbitrary string data
|
||||
*/
|
||||
public static void reportUsage(String resource, String data) {
|
||||
getCameraServerShared().reportUsage(resource, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CameraServerShared object.
|
||||
*
|
||||
|
||||
@@ -73,7 +73,7 @@ public class VisionRunner<P extends VisionPipeline> {
|
||||
public void runOnce() {
|
||||
Long id = CameraServerSharedStore.getCameraServerShared().getRobotMainThreadId();
|
||||
|
||||
if (id != null && Thread.currentThread().threadId() == id) {
|
||||
if (id != null && Thread.currentThread().getId() == id) {
|
||||
throw new IllegalStateException(
|
||||
"VisionRunner.runOnce() cannot be called from the main robot thread");
|
||||
}
|
||||
@@ -106,7 +106,7 @@ public class VisionRunner<P extends VisionPipeline> {
|
||||
public void runForever() {
|
||||
Long id = CameraServerSharedStore.getCameraServerShared().getRobotMainThreadId();
|
||||
|
||||
if (id != null && Thread.currentThread().threadId() == id) {
|
||||
if (id != null && Thread.currentThread().getId() == id) {
|
||||
throw new IllegalStateException(
|
||||
"VisionRunner.runForever() cannot be called from the main robot thread");
|
||||
}
|
||||
|
||||
@@ -184,9 +184,9 @@ std::vector<std::string> Instance::GetSourceStreamValues(CS_Source source) {
|
||||
value = "mjpg:" + value;
|
||||
}
|
||||
|
||||
#ifdef __FRC_SYSTEMCORE__
|
||||
#ifdef __FRC_ROBORIO__
|
||||
// Look to see if we have a passthrough server for this source
|
||||
// Only do this on the systemcore
|
||||
// Only do this on the roboRIO
|
||||
for (const auto& i : m_sinks) {
|
||||
CS_Sink sink = i.second.GetHandle();
|
||||
CS_Source sinkSource = cs::GetSinkSource(sink, &status);
|
||||
@@ -471,7 +471,11 @@ Instance::Instance() {
|
||||
}
|
||||
|
||||
cs::UsbCamera CameraServer::StartAutomaticCapture() {
|
||||
return StartAutomaticCapture(::GetInstance().m_defaultUsbDevice++);
|
||||
cs::UsbCamera camera =
|
||||
StartAutomaticCapture(::GetInstance().m_defaultUsbDevice++);
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->ReportUsbCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::UsbCamera CameraServer::StartAutomaticCapture(int dev) {
|
||||
@@ -479,7 +483,7 @@ cs::UsbCamera CameraServer::StartAutomaticCapture(int dev) {
|
||||
cs::UsbCamera camera{fmt::format("USB Camera {}", dev), dev};
|
||||
StartAutomaticCapture(camera);
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->ReportUsage(fmt::format("UsbCamera[{}]", dev), "auto");
|
||||
csShared->ReportUsbCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
@@ -489,7 +493,7 @@ cs::UsbCamera CameraServer::StartAutomaticCapture(std::string_view name,
|
||||
cs::UsbCamera camera{name, dev};
|
||||
StartAutomaticCapture(camera);
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->ReportUsage(fmt::format("UsbCamera[{}]", dev), "name");
|
||||
csShared->ReportUsbCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
@@ -499,10 +503,67 @@ cs::UsbCamera CameraServer::StartAutomaticCapture(std::string_view name,
|
||||
cs::UsbCamera camera{name, path};
|
||||
StartAutomaticCapture(camera);
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->ReportUsage(fmt::format("UsbCamera[{}]", path), "path");
|
||||
csShared->ReportUsbCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
WPI_IGNORE_DEPRECATED
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::string_view host) {
|
||||
return AddAxisCamera("Axis Camera", host);
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(const char* host) {
|
||||
return AddAxisCamera("Axis Camera", host);
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(const std::string& host) {
|
||||
return AddAxisCamera("Axis Camera", host);
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::span<const std::string> hosts) {
|
||||
return AddAxisCamera("Axis Camera", hosts);
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
|
||||
std::string_view host) {
|
||||
::GetInstance();
|
||||
cs::AxisCamera camera{name, host};
|
||||
StartAutomaticCapture(camera);
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->ReportAxisCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
|
||||
const char* host) {
|
||||
::GetInstance();
|
||||
cs::AxisCamera camera{name, host};
|
||||
StartAutomaticCapture(camera);
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->ReportAxisCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
|
||||
const std::string& host) {
|
||||
::GetInstance();
|
||||
cs::AxisCamera camera{name, host};
|
||||
StartAutomaticCapture(camera);
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->ReportAxisCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
|
||||
std::span<const std::string> hosts) {
|
||||
::GetInstance();
|
||||
cs::AxisCamera camera{name, hosts};
|
||||
StartAutomaticCapture(camera);
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->ReportAxisCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
WPI_UNIGNORE_DEPRECATED
|
||||
cs::MjpegServer CameraServer::AddSwitchedCamera(std::string_view name) {
|
||||
auto& inst = ::GetInstance();
|
||||
// create a dummy CvSource
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
namespace {
|
||||
class DefaultCameraServerShared : public frc::CameraServerShared {
|
||||
public:
|
||||
void ReportUsage(std::string_view resource, std::string_view data) override {}
|
||||
void ReportUsbCamera(int id) override {}
|
||||
void ReportAxisCamera(int id) override {}
|
||||
void ReportVideoServer(int id) override {}
|
||||
void SetCameraServerErrorV(fmt::string_view format,
|
||||
fmt::format_args args) override {}
|
||||
void SetVisionRunnerErrorV(fmt::string_view format,
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/deprecated.h>
|
||||
|
||||
#include "cscore_cv.h"
|
||||
|
||||
namespace frc {
|
||||
@@ -73,6 +75,128 @@ class CameraServer {
|
||||
*/
|
||||
static cs::MjpegServer StartAutomaticCapture(const cs::VideoSource& camera);
|
||||
|
||||
WPI_IGNORE_DEPRECATED
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* This overload calls AddAxisCamera() with name "Axis Camera".
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* This overload calls AddAxisCamera() with name "Axis Camera".
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(const char* host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* This overload calls AddAxisCamera() with name "Axis Camera".
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(const std::string& host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* This overload calls AddAxisCamera() with name "Axis Camera".
|
||||
*
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::span<const std::string> hosts);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* This overload calls AddAxisCamera() with name "Axis Camera".
|
||||
*
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
template <typename T>
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::initializer_list<T> hosts) {
|
||||
return AddAxisCamera("Axis Camera", hosts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
std::string_view host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name, const char* host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
const std::string& host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
std::span<const std::string> hosts);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
template <typename T>
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
std::initializer_list<T> hosts) {
|
||||
std::vector<std::string> vec;
|
||||
vec.reserve(hosts.size());
|
||||
for (const auto& host : hosts) {
|
||||
vec.emplace_back(host);
|
||||
}
|
||||
return AddAxisCamera(name, vec);
|
||||
}
|
||||
WPI_UNIGNORE_DEPRECATED
|
||||
|
||||
/**
|
||||
* Adds a virtual camera for switching between two streams. Unlike the
|
||||
* other addCamera methods, this returns a VideoSink rather than a
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
@@ -15,8 +14,9 @@ namespace frc {
|
||||
class CameraServerShared {
|
||||
public:
|
||||
virtual ~CameraServerShared() = default;
|
||||
virtual void ReportUsage(std::string_view resource,
|
||||
std::string_view data) = 0;
|
||||
virtual void ReportUsbCamera(int id) = 0;
|
||||
virtual void ReportAxisCamera(int id) = 0;
|
||||
virtual void ReportVideoServer(int id) = 0;
|
||||
virtual void SetCameraServerErrorV(fmt::string_view format,
|
||||
fmt::format_args args) = 0;
|
||||
virtual void SetVisionRunnerErrorV(fmt::string_view format,
|
||||
|
||||
@@ -17,7 +17,7 @@ macro(add_doxygen_docs)
|
||||
foreach(dir ${dirs})
|
||||
list(APPEND docs_dirs ${dir}/src/main/native/include)
|
||||
file(GLOB dirs ${dir}/src/main/native/thirdparty/*/include)
|
||||
list(FILTER dirs EXCLUDE REGEX eigen)
|
||||
list(FILTER dirs EXCLUDE REGEX eigen|protobuf)
|
||||
set(DOXYGEN_EXCLUDE_PATTERNS "*.pb.h" "**/.clang-tidy" "**/.clang-format")
|
||||
|
||||
if(DOCS_WARNINGS_AS_ERRORS)
|
||||
@@ -45,9 +45,11 @@ macro(add_doxygen_docs)
|
||||
"wpi/fs.h"
|
||||
"wpi/FunctionExtras.h"
|
||||
"wpi/function_ref.h"
|
||||
"wpi/Hashing.h"
|
||||
"wpi/iterator.h"
|
||||
"wpi/iterator_range.h"
|
||||
"wpi/ManagedStatic.h"
|
||||
"wpi/MapVector.h"
|
||||
"wpi/MathExtras.h"
|
||||
"wpi/MemAlloc.h"
|
||||
"wpi/PointerIntPair.h"
|
||||
|
||||
@@ -2,6 +2,9 @@ include(CompileWarnings)
|
||||
|
||||
macro(wpilib_add_test name srcdir)
|
||||
file(GLOB_RECURSE test_src ${srcdir}/*.cpp)
|
||||
if(NOT WITH_PROTOBUF)
|
||||
list(FILTER test_src EXCLUDE REGEX "/proto/")
|
||||
endif()
|
||||
add_executable(${name}_test ${test_src})
|
||||
set_property(TARGET ${name}_test PROPERTY FOLDER "tests")
|
||||
wpilib_target_warnings(${name}_test)
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
modifiableFileExclude {
|
||||
\.patch$
|
||||
}
|
||||
|
||||
generatedFileExclude {
|
||||
src/generated/main/java/org/wpilib/commands3/button/
|
||||
src/generated/main/java/org/wpilib/commands3/proto/
|
||||
}
|
||||
|
||||
repoRootNameOverride {
|
||||
commandsv3
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
load("@allwpilib_pip_deps//:requirements.bzl", "requirement")
|
||||
load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files")
|
||||
load("@rules_java//java:defs.bzl", "java_binary")
|
||||
load("@rules_python//python:defs.bzl", "py_binary")
|
||||
load("//commandsv3:generate.bzl", "generate_commandsv3")
|
||||
load("//shared/bazel/rules:java_rules.bzl", "wpilib_java_junit5_test", "wpilib_java_library")
|
||||
|
||||
py_binary(
|
||||
name = "generate_files",
|
||||
srcs = ["generate_files.py"],
|
||||
target_compatible_with = select({
|
||||
"@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
deps = [requirement("jinja2")],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "templates",
|
||||
srcs = glob(["src/generate/main/**"]) + [
|
||||
"//wpilibj:hid_schema",
|
||||
],
|
||||
)
|
||||
|
||||
generate_commandsv3(
|
||||
name = "generate_commandsv3",
|
||||
)
|
||||
|
||||
write_source_files(
|
||||
name = "write_commandsv3",
|
||||
files = {
|
||||
"src/generated": ":generate_commandsv3",
|
||||
},
|
||||
suggested_update_target = "//:write_all",
|
||||
tags = ["pregeneration"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "generated_java",
|
||||
srcs = glob(["src/generated/main/java/**/*.java"]),
|
||||
)
|
||||
|
||||
wpilib_java_library(
|
||||
name = "commandsv3-java",
|
||||
srcs = glob(["src/main/java/**/*.java"]) + [":generated_java"],
|
||||
exported_plugins = ["//javacPlugin:plugin"],
|
||||
maven_artifact_name = "commands3-java",
|
||||
maven_group_id = "org.wpilib.commands3",
|
||||
plugins = ["//javacPlugin:plugin"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cscore:cscore-java",
|
||||
"//hal:hal-java",
|
||||
"//ntcore:ntcore-java",
|
||||
"//wpiannotations",
|
||||
"//wpilibj:wpilibj-java",
|
||||
"//wpimath:wpimath-java",
|
||||
"//wpinet:wpinet-java",
|
||||
"//wpiunits:wpiunits-java",
|
||||
"//wpiutil:wpiutil-java",
|
||||
"@maven//:us_hebi_quickbuf_quickbuf_runtime",
|
||||
],
|
||||
)
|
||||
|
||||
wpilib_java_junit5_test(
|
||||
name = "commandsv3-java-test",
|
||||
srcs = glob(["**/*.java"]),
|
||||
deps = [
|
||||
":commandsv3-java",
|
||||
"//hal:hal-java",
|
||||
"//ntcore:ntcore-java",
|
||||
"//wpiannotations",
|
||||
"//wpilibj:wpilibj-java",
|
||||
"//wpimath:wpimath-java",
|
||||
"//wpiunits:wpiunits-java",
|
||||
"//wpiutil:wpiutil-java",
|
||||
"@maven//:us_hebi_quickbuf_quickbuf_runtime",
|
||||
],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "DevMain-Java",
|
||||
srcs = ["src/dev/java/org/wpilib/commands3/DevMain.java"],
|
||||
main_class = "org.wpilib.commands3.DevMain",
|
||||
deps = [
|
||||
"//hal:hal-java",
|
||||
"//ntcore:ntcore-java",
|
||||
"//wpimath:wpimath-java",
|
||||
"//wpiutil:wpiutil-java",
|
||||
],
|
||||
)
|
||||
@@ -1,53 +0,0 @@
|
||||
project(commandsv3)
|
||||
|
||||
include(SubDirList)
|
||||
include(CompileWarnings)
|
||||
include(AddTest)
|
||||
|
||||
if(WITH_JAVA)
|
||||
include(UseJava)
|
||||
|
||||
file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java src/generated/main/java/*.java)
|
||||
file(GLOB QUICKBUF_JAR ${WPILIB_BINARY_DIR}/wpiutil/thirdparty/quickbuf/*.jar)
|
||||
|
||||
add_jar(
|
||||
commandsv3_jar
|
||||
${JAVA_SOURCES}
|
||||
INCLUDE_JARS
|
||||
datalog_jar
|
||||
hal_jar
|
||||
ntcore_jar
|
||||
cscore_jar
|
||||
cameraserver_jar
|
||||
wpiannotations_jar
|
||||
wpimath_jar
|
||||
wpiunits_jar
|
||||
wpiutil_jar
|
||||
wpilibj_jar
|
||||
${QUICKBUF_JAR}
|
||||
OUTPUT_NAME commandsv3
|
||||
OUTPUT_DIR ${WPILIB_BINARY_DIR}/${java_lib_dest}
|
||||
)
|
||||
|
||||
install_jar(commandsv3_jar DESTINATION ${java_lib_dest})
|
||||
install_jar_exports(
|
||||
TARGETS commandsv3_jar
|
||||
FILE commandsv3_jar.cmake
|
||||
DESTINATION share/commandsv3
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_JAVA_SOURCE)
|
||||
include(UseJava)
|
||||
include(CreateSourceJar)
|
||||
add_source_jar(
|
||||
commandsv3_src_jar
|
||||
BASE_DIRECTORIES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/main/java
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/generated/main/java
|
||||
OUTPUT_NAME commandsv3-sources
|
||||
OUTPUT_DIR ${WPILIB_BINARY_DIR}/${java_lib_dest}
|
||||
)
|
||||
set_property(TARGET commandsv3_src_jar PROPERTY FOLDER "java")
|
||||
install_jar(commandsv3_src_jar DESTINATION ${java_lib_dest})
|
||||
endif()
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"fileName": "CommandsV3.json",
|
||||
"name": "Commands v3",
|
||||
"version": "1.0.0",
|
||||
"uuid": "4decdc05-a056-46cf-9561-39449bbb0130",
|
||||
"frcYear": "2027_alpha1",
|
||||
"mavenUrls": [],
|
||||
"jsonUrl": "",
|
||||
"javaDependencies": [
|
||||
{
|
||||
"groupId": "org.wpilib.commands3",
|
||||
"artifactId": "commands3-java",
|
||||
"version": "wpilib"
|
||||
}
|
||||
],
|
||||
"jniDependencies": [],
|
||||
"cppDependencies": []
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
ext {
|
||||
useJava = true
|
||||
useCpp = false
|
||||
baseId = 'commands3'
|
||||
groupId = 'org.wpilib'
|
||||
|
||||
nativeName = 'commands3'
|
||||
devMain = 'org.wpilib.commands3.DevMain'
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/shared/java/javacommon.gradle"
|
||||
|
||||
evaluationDependsOn(':wpiutil')
|
||||
evaluationDependsOn(':ntcore')
|
||||
evaluationDependsOn(':hal')
|
||||
evaluationDependsOn(':wpimath')
|
||||
evaluationDependsOn(':wpilibj')
|
||||
|
||||
dependencies {
|
||||
annotationProcessor project(':javacPlugin')
|
||||
implementation project(':wpiannotations')
|
||||
implementation project(':wpiutil')
|
||||
implementation project(':wpinet')
|
||||
implementation project(':ntcore')
|
||||
implementation project(':hal')
|
||||
implementation project(':wpimath')
|
||||
implementation project(':wpilibj')
|
||||
api("us.hebi.quickbuf:quickbuf-runtime:1.4")
|
||||
testAnnotationProcessor project(':javacPlugin')
|
||||
testImplementation 'org.mockito:mockito-core:4.1.0'
|
||||
}
|
||||
|
||||
sourceSets.main.java.srcDir "${projectDir}/src/generated/main/java"
|
||||
sourceSets.main.resources.srcDir "${projectDir}/src/main/proto"
|
||||
|
||||
test {
|
||||
testLogging {
|
||||
outputs.upToDateWhen {false}
|
||||
showStandardStreams = true
|
||||
}
|
||||
|
||||
// For reflective access to the continuation classes
|
||||
jvmArgs += [
|
||||
'--add-opens',
|
||||
'java.base/jdk.internal.vm=ALL-UNNAMED',
|
||||
'--add-opens',
|
||||
'java.base/java.lang=ALL-UNNAMED',
|
||||
]
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
@WPIUTIL_DEP_REPLACE@
|
||||
@DATALOG_DEP_REPLACE@
|
||||
@NTCORE_DEP_REPLACE@
|
||||
@CSCORE_DEP_REPLACE@
|
||||
@CAMERASERVER_DEP_REPLACE@
|
||||
@HAL_DEP_REPLACE@
|
||||
@WPILIBC_DEP_REPLACE@
|
||||
@WPIMATH_DEP_REPLACE@
|
||||
|
||||
@FILENAME_DEP_REPLACE@
|
||||
include(${SELF_DIR}/commandsv3.cmake)
|
||||
if(@WITH_JAVA@)
|
||||
include(${SELF_DIR}/commandsv3_jar.cmake)
|
||||
endif()
|
||||
@@ -1,45 +0,0 @@
|
||||
def __generate_commandsv3_impl(ctx):
|
||||
"""
|
||||
Custom rule used to create the commandsv3 pre-generated files. See `./README-Bazel.md` for the reasoning.
|
||||
"""
|
||||
output_dir = ctx.actions.declare_directory("_gendir")
|
||||
|
||||
args = ctx.actions.args()
|
||||
args.add("--output_directory", output_dir.path)
|
||||
args.add("--template_root", "commandsv3/src/generate")
|
||||
args.add("--protoc", ctx.executable._protoc)
|
||||
args.add("--quickbuf_plugin", ctx.executable._quickbuf)
|
||||
|
||||
ctx.actions.run(
|
||||
inputs = ctx.attr._templates.files,
|
||||
outputs = [output_dir],
|
||||
executable = ctx.executable._tool,
|
||||
arguments = [args],
|
||||
tools = [ctx.executable._protoc, ctx.executable._quickbuf],
|
||||
)
|
||||
|
||||
return [DefaultInfo(files = depset([output_dir]))]
|
||||
|
||||
generate_commandsv3 = rule(
|
||||
implementation = __generate_commandsv3_impl,
|
||||
attrs = {
|
||||
"_protoc": attr.label(
|
||||
default = Label("@com_google_protobuf//:protoc"),
|
||||
cfg = "exec",
|
||||
executable = True,
|
||||
),
|
||||
"_quickbuf": attr.label(
|
||||
default = Label("//:quickbuf_protoc"),
|
||||
cfg = "exec",
|
||||
executable = True,
|
||||
),
|
||||
"_templates": attr.label(
|
||||
default = Label("//commandsv3:templates"),
|
||||
),
|
||||
"_tool": attr.label(
|
||||
default = Label("//commandsv3:generate_files"),
|
||||
cfg = "exec",
|
||||
executable = True,
|
||||
),
|
||||
},
|
||||
)
|
||||
@@ -1,120 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) FIRST and other WPILib contributors.
|
||||
# Open Source Software; you can modify and/or share it under the terms of
|
||||
# the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
|
||||
def write_controller_file(output_dir: Path, controller_name: str, contents: str):
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
output_file = output_dir / controller_name
|
||||
output_file.write_text(contents, encoding="utf-8", newline="\n")
|
||||
print("Writing to ", output_file)
|
||||
|
||||
|
||||
def generate_hids(output_directory: Path, template_directory: Path, schema_file: Path):
|
||||
with schema_file.open(encoding="utf-8") as f:
|
||||
controllers = json.load(f)
|
||||
|
||||
# Java files
|
||||
java_subdirectory = "main/java/org/wpilib/commands3/button"
|
||||
env = Environment(
|
||||
loader=FileSystemLoader(template_directory / "main/java"),
|
||||
autoescape=False,
|
||||
keep_trailing_newline=True,
|
||||
)
|
||||
root_path = output_directory / java_subdirectory
|
||||
template = env.get_template("commandhid.java.jinja")
|
||||
for controller in controllers:
|
||||
controllerName = f"Command{controller['ConsoleName']}Controller.java"
|
||||
output = template.render(controller)
|
||||
write_controller_file(root_path, controllerName, output)
|
||||
|
||||
|
||||
def generate_quickbuf(
|
||||
protoc, quickbuf_plugin: Path, output_directory: Path, proto_dir: Path
|
||||
):
|
||||
proto_files = proto_dir.glob("*.proto")
|
||||
for path in proto_files:
|
||||
absolute_filename = path.absolute()
|
||||
args = [protoc]
|
||||
if quickbuf_plugin:
|
||||
# Optional on macOS if using protoc-quickbuf
|
||||
args += [f"--plugin=protoc-gen-quickbuf={quickbuf_plugin}"]
|
||||
args += [
|
||||
f"--quickbuf_out=gen_descriptors=true:{output_directory.absolute()}",
|
||||
f"-I{absolute_filename.parent}",
|
||||
absolute_filename,
|
||||
]
|
||||
subprocess.check_call(args)
|
||||
java_files = (output_directory / "org/wpilib/commands3/proto").glob("*.java")
|
||||
for java_file in java_files:
|
||||
with (java_file).open(encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
java_file.write_text(
|
||||
"// Copyright (c) FIRST and other WPILib contributors.\n// Open Source Software; you can modify and/or share it under the terms of\n// the WPILib BSD license file in the root directory of this project.\n"
|
||||
+ content,
|
||||
encoding="utf-8",
|
||||
newline="\n",
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
script_path = Path(__file__).resolve()
|
||||
dirname = script_path.parent
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--output_directory",
|
||||
help="Optional. If set, will output the generated files to this directory, otherwise it will use a path relative to the script",
|
||||
default=dirname / "src/generated",
|
||||
type=Path,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--template_root",
|
||||
help="Optional. If set, will use this directory as the root for the jinja templates",
|
||||
default=dirname / "src/generate",
|
||||
type=Path,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--schema_file",
|
||||
help="Optional. If set, will use this file for the joystick schema",
|
||||
default="wpilibj/src/generate/hids.json",
|
||||
type=Path,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--protoc",
|
||||
help="Protoc executable command",
|
||||
default="protoc",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--quickbuf_plugin",
|
||||
help="Path to the quickbuf protoc plugin",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--proto_directory",
|
||||
help="Optional. If set, will use this directory to glob for protobuf files",
|
||||
default=dirname / "src/main/proto",
|
||||
type=Path,
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
generate_hids(args.output_directory, args.template_root, args.schema_file)
|
||||
generate_quickbuf(
|
||||
args.protoc,
|
||||
args.quickbuf_plugin,
|
||||
args.output_directory / "main/java",
|
||||
args.proto_directory,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,23 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
import edu.wpi.first.hal.HALUtil;
|
||||
import edu.wpi.first.networktables.NetworkTablesJNI;
|
||||
import edu.wpi.first.util.CombinedRuntimeLoader;
|
||||
|
||||
/** Dev main. */
|
||||
public final class DevMain {
|
||||
/** Main entry point. */
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Commands V3 DevMain");
|
||||
|
||||
System.out.println(CombinedRuntimeLoader.getPlatformPath());
|
||||
System.out.println(NetworkTablesJNI.now());
|
||||
System.out.println(HALUtil.getHALRuntimeType());
|
||||
}
|
||||
|
||||
private DevMain() {}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
// THIS FILE WAS AUTO-GENERATED BY ./commandsv3/generate_files.py. DO NOT MODIFY
|
||||
{% macro capitalize_first(string) -%}
|
||||
{{ string[0]|capitalize + string[1:] }}
|
||||
{%- endmacro %}
|
||||
package org.wpilib.commands3.button;
|
||||
|
||||
import edu.wpi.first.wpilibj.{{ ConsoleName }}Controller;
|
||||
import edu.wpi.first.wpilibj.event.EventLoop;
|
||||
import org.wpilib.commands3.Scheduler;
|
||||
import org.wpilib.commands3.Trigger;
|
||||
|
||||
/**
|
||||
* A version of {@link {{ ConsoleName }}Controller} with {@link Trigger} factories for command-based.
|
||||
*
|
||||
* @see {{ ConsoleName }}Controller
|
||||
*/
|
||||
@SuppressWarnings("MethodName")
|
||||
public class Command{{ ConsoleName }}Controller extends CommandGenericHID {
|
||||
private final {{ ConsoleName }}Controller m_hid;
|
||||
|
||||
/**
|
||||
* Construct an instance of a controller. Commands bound to buttons on the controller will be
|
||||
* scheduled on the {@link Scheduler#getDefault() default scheduler} using its default event loop.
|
||||
*
|
||||
* @param port The port index on the Driver Station that the controller is plugged into.
|
||||
*/
|
||||
public Command{{ ConsoleName }}Controller(int port) {
|
||||
super(port);
|
||||
m_hid = new {{ ConsoleName }}Controller(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance of a controller. Commands bound to buttons on the controller will be
|
||||
* scheduled on the given scheduler using its default event loop.
|
||||
*
|
||||
* @param scheduler The scheduler that should execute the triggered commands.
|
||||
* @param port The port index on the Driver Station that the controller is plugged into.
|
||||
*/
|
||||
public Command{{ ConsoleName }}Controller(Scheduler scheduler, int port) {
|
||||
super(scheduler, port);
|
||||
m_hid = new {{ ConsoleName }}Controller(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying GenericHID object.
|
||||
*
|
||||
* @return the wrapped GenericHID object
|
||||
*/
|
||||
@Override
|
||||
public {{ ConsoleName }}Controller getHID() {
|
||||
return m_hid;
|
||||
}
|
||||
{% for button in buttons %}
|
||||
/**
|
||||
* Constructs a Trigger instance around the {{ button.DocName|default(button.name) }} button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the {{ button.DocName|default(button.name) }} button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #{{ button.name }}(EventLoop)
|
||||
*/
|
||||
public Trigger {{ button.name }}() {
|
||||
return {{ button.name }}(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the {{ button.DocName|default(button.name) }} button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the {{ button.DocName|default(button.name) }} button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger {{ button.name }}(EventLoop loop) {
|
||||
return button({{ ConsoleName }}Controller.Button.k{{ capitalize_first(button.name) }}.value, loop);
|
||||
}
|
||||
{% endfor -%}
|
||||
{% for trigger in triggers -%}
|
||||
{% if trigger.UseThresholdMethods %}
|
||||
/**
|
||||
* Constructs a Trigger instance around the axis value of the {{ trigger.DocName }}. The returned
|
||||
* trigger will be true when the axis value is greater than {@code threshold}.
|
||||
*
|
||||
* @param threshold the minimum axis value for the returned {@link Trigger} to be true. This value
|
||||
* should be in the range [0, 1] where 0 is the unpressed state of the axis.
|
||||
* @param loop the event loop instance to attach the Trigger to.
|
||||
* @return a Trigger instance that is true when the {{ trigger.DocName }}'s axis exceeds the provided
|
||||
* threshold, attached to the given event loop
|
||||
*/
|
||||
public Trigger {{ trigger.name }}(double threshold, EventLoop loop) {
|
||||
return axisGreaterThan({{ ConsoleName }}Controller.Axis.k{{ capitalize_first(trigger.name) }}.value, threshold, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the axis value of the {{ trigger.DocName }}. The returned
|
||||
* trigger will be true when the axis value is greater than {@code threshold}.
|
||||
*
|
||||
* @param threshold the minimum axis value for the returned {@link Trigger} to be true. This value
|
||||
* should be in the range [0, 1] where 0 is the unpressed state of the axis.
|
||||
* @return a Trigger instance that is true when the {{ trigger.DocName }}'s axis exceeds the provided
|
||||
* threshold, attached to the {@link Scheduler#getDefaultEventLoop() default scheduler event
|
||||
* loop} on the scheduler passed to the controller's constructor, or the {@link
|
||||
* Scheduler#getDefault default scheduler} if a scheduler was not explicitly provided.
|
||||
*/
|
||||
public Trigger {{ trigger.name }}(double threshold) {
|
||||
return {{ trigger.name }}(threshold, getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the axis value of the {{ trigger.DocName }}. The returned trigger
|
||||
* will be true when the axis value is greater than 0.5.
|
||||
*
|
||||
* @return a Trigger instance that is true when the {{ trigger.DocName }}'s axis exceeds 0.5, attached to
|
||||
* the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
*/
|
||||
public Trigger {{ trigger.name }}() {
|
||||
return {{ trigger.name }}(0.5);
|
||||
}
|
||||
{% endif -%}
|
||||
{% endfor -%}
|
||||
{% for stick in sticks %}
|
||||
/**
|
||||
* Get the {{ stick.NameParts[1] }} axis value of {{ stick.NameParts[0] }} side of the controller. {{ stick.PositiveDirection }} is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double get{{ stick.NameParts|map("capitalize")|join }}() {
|
||||
return m_hid.get{{ stick.NameParts|map("capitalize")|join }}();
|
||||
}
|
||||
{% endfor -%}
|
||||
{% for trigger in triggers %}
|
||||
/**
|
||||
* Get the {{ trigger.DocName }} axis value of the controller. Note that this axis is bound to the
|
||||
* range of [0, 1] as opposed to the usual [-1, 1].
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double get{{ capitalize_first(trigger.name) }}Axis() {
|
||||
return m_hid.get{{ capitalize_first(trigger.name) }}Axis();
|
||||
}
|
||||
{% endfor -%}
|
||||
}
|
||||
@@ -1,447 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
// THIS FILE WAS AUTO-GENERATED BY ./commandsv3/generate_files.py. DO NOT MODIFY
|
||||
|
||||
package org.wpilib.commands3.button;
|
||||
|
||||
import edu.wpi.first.wpilibj.PS4Controller;
|
||||
import edu.wpi.first.wpilibj.event.EventLoop;
|
||||
import org.wpilib.commands3.Scheduler;
|
||||
import org.wpilib.commands3.Trigger;
|
||||
|
||||
/**
|
||||
* A version of {@link PS4Controller} with {@link Trigger} factories for command-based.
|
||||
*
|
||||
* @see PS4Controller
|
||||
*/
|
||||
@SuppressWarnings("MethodName")
|
||||
public class CommandPS4Controller extends CommandGenericHID {
|
||||
private final PS4Controller m_hid;
|
||||
|
||||
/**
|
||||
* Construct an instance of a controller. Commands bound to buttons on the controller will be
|
||||
* scheduled on the {@link Scheduler#getDefault() default scheduler} using its default event loop.
|
||||
*
|
||||
* @param port The port index on the Driver Station that the controller is plugged into.
|
||||
*/
|
||||
public CommandPS4Controller(int port) {
|
||||
super(port);
|
||||
m_hid = new PS4Controller(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance of a controller. Commands bound to buttons on the controller will be
|
||||
* scheduled on the given scheduler using its default event loop.
|
||||
*
|
||||
* @param scheduler The scheduler that should execute the triggered commands.
|
||||
* @param port The port index on the Driver Station that the controller is plugged into.
|
||||
*/
|
||||
public CommandPS4Controller(Scheduler scheduler, int port) {
|
||||
super(scheduler, port);
|
||||
m_hid = new PS4Controller(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying GenericHID object.
|
||||
*
|
||||
* @return the wrapped GenericHID object
|
||||
*/
|
||||
@Override
|
||||
public PS4Controller getHID() {
|
||||
return m_hid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the square button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the square button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #square(EventLoop)
|
||||
*/
|
||||
public Trigger square() {
|
||||
return square(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the square button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the square button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger square(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kSquare.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the cross button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the cross button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #cross(EventLoop)
|
||||
*/
|
||||
public Trigger cross() {
|
||||
return cross(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the cross button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the cross button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger cross(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kCross.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the circle button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the circle button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #circle(EventLoop)
|
||||
*/
|
||||
public Trigger circle() {
|
||||
return circle(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the circle button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the circle button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger circle(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kCircle.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the triangle button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the triangle button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #triangle(EventLoop)
|
||||
*/
|
||||
public Trigger triangle() {
|
||||
return triangle(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the triangle button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the triangle button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger triangle(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kTriangle.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left trigger 1 button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the left trigger 1 button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #L1(EventLoop)
|
||||
*/
|
||||
public Trigger L1() {
|
||||
return L1(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left trigger 1 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the left trigger 1 button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger L1(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kL1.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right trigger 1 button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the right trigger 1 button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #R1(EventLoop)
|
||||
*/
|
||||
public Trigger R1() {
|
||||
return R1(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right trigger 1 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the right trigger 1 button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger R1(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kR1.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left trigger 2 button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the left trigger 2 button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #L2(EventLoop)
|
||||
*/
|
||||
public Trigger L2() {
|
||||
return L2(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left trigger 2 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the left trigger 2 button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger L2(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kL2.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right trigger 2 button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the right trigger 2 button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #R2(EventLoop)
|
||||
*/
|
||||
public Trigger R2() {
|
||||
return R2(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right trigger 2 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the right trigger 2 button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger R2(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kR2.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the share button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the share button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #share(EventLoop)
|
||||
*/
|
||||
public Trigger share() {
|
||||
return share(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the share button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the share button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger share(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kShare.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the options button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the options button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #options(EventLoop)
|
||||
*/
|
||||
public Trigger options() {
|
||||
return options(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the options button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the options button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger options(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kOptions.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the L3 (left stick) button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the L3 (left stick) button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #L3(EventLoop)
|
||||
*/
|
||||
public Trigger L3() {
|
||||
return L3(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the L3 (left stick) button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the L3 (left stick) button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger L3(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kL3.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the R3 (right stick) button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the R3 (right stick) button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #R3(EventLoop)
|
||||
*/
|
||||
public Trigger R3() {
|
||||
return R3(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the R3 (right stick) button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the R3 (right stick) button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger R3(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kR3.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the PlayStation button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the PlayStation button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #PS(EventLoop)
|
||||
*/
|
||||
public Trigger PS() {
|
||||
return PS(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the PlayStation button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the PlayStation button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger PS(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kPS.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the touchpad button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the touchpad button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #touchpad(EventLoop)
|
||||
*/
|
||||
public Trigger touchpad() {
|
||||
return touchpad(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the touchpad button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the touchpad button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger touchpad(EventLoop loop) {
|
||||
return button(PS4Controller.Button.kTouchpad.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X axis value of left side of the controller. Right is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getLeftX() {
|
||||
return m_hid.getLeftX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y axis value of left side of the controller. Back is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getLeftY() {
|
||||
return m_hid.getLeftY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X axis value of right side of the controller. Right is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getRightX() {
|
||||
return m_hid.getRightX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y axis value of right side of the controller. Back is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getRightY() {
|
||||
return m_hid.getRightY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the left trigger 2 axis value of the controller. Note that this axis is bound to the
|
||||
* range of [0, 1] as opposed to the usual [-1, 1].
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getL2Axis() {
|
||||
return m_hid.getL2Axis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the right trigger 2 axis value of the controller. Note that this axis is bound to the
|
||||
* range of [0, 1] as opposed to the usual [-1, 1].
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getR2Axis() {
|
||||
return m_hid.getR2Axis();
|
||||
}
|
||||
}
|
||||
@@ -1,447 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
// THIS FILE WAS AUTO-GENERATED BY ./commandsv3/generate_files.py. DO NOT MODIFY
|
||||
|
||||
package org.wpilib.commands3.button;
|
||||
|
||||
import edu.wpi.first.wpilibj.PS5Controller;
|
||||
import edu.wpi.first.wpilibj.event.EventLoop;
|
||||
import org.wpilib.commands3.Scheduler;
|
||||
import org.wpilib.commands3.Trigger;
|
||||
|
||||
/**
|
||||
* A version of {@link PS5Controller} with {@link Trigger} factories for command-based.
|
||||
*
|
||||
* @see PS5Controller
|
||||
*/
|
||||
@SuppressWarnings("MethodName")
|
||||
public class CommandPS5Controller extends CommandGenericHID {
|
||||
private final PS5Controller m_hid;
|
||||
|
||||
/**
|
||||
* Construct an instance of a controller. Commands bound to buttons on the controller will be
|
||||
* scheduled on the {@link Scheduler#getDefault() default scheduler} using its default event loop.
|
||||
*
|
||||
* @param port The port index on the Driver Station that the controller is plugged into.
|
||||
*/
|
||||
public CommandPS5Controller(int port) {
|
||||
super(port);
|
||||
m_hid = new PS5Controller(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance of a controller. Commands bound to buttons on the controller will be
|
||||
* scheduled on the given scheduler using its default event loop.
|
||||
*
|
||||
* @param scheduler The scheduler that should execute the triggered commands.
|
||||
* @param port The port index on the Driver Station that the controller is plugged into.
|
||||
*/
|
||||
public CommandPS5Controller(Scheduler scheduler, int port) {
|
||||
super(scheduler, port);
|
||||
m_hid = new PS5Controller(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying GenericHID object.
|
||||
*
|
||||
* @return the wrapped GenericHID object
|
||||
*/
|
||||
@Override
|
||||
public PS5Controller getHID() {
|
||||
return m_hid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the square button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the square button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #square(EventLoop)
|
||||
*/
|
||||
public Trigger square() {
|
||||
return square(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the square button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the square button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger square(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kSquare.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the cross button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the cross button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #cross(EventLoop)
|
||||
*/
|
||||
public Trigger cross() {
|
||||
return cross(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the cross button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the cross button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger cross(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kCross.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the circle button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the circle button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #circle(EventLoop)
|
||||
*/
|
||||
public Trigger circle() {
|
||||
return circle(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the circle button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the circle button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger circle(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kCircle.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the triangle button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the triangle button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #triangle(EventLoop)
|
||||
*/
|
||||
public Trigger triangle() {
|
||||
return triangle(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the triangle button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the triangle button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger triangle(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kTriangle.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left trigger 1 button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the left trigger 1 button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #L1(EventLoop)
|
||||
*/
|
||||
public Trigger L1() {
|
||||
return L1(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left trigger 1 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the left trigger 1 button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger L1(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kL1.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right trigger 1 button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the right trigger 1 button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #R1(EventLoop)
|
||||
*/
|
||||
public Trigger R1() {
|
||||
return R1(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right trigger 1 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the right trigger 1 button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger R1(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kR1.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left trigger 2 button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the left trigger 2 button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #L2(EventLoop)
|
||||
*/
|
||||
public Trigger L2() {
|
||||
return L2(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left trigger 2 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the left trigger 2 button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger L2(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kL2.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right trigger 2 button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the right trigger 2 button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #R2(EventLoop)
|
||||
*/
|
||||
public Trigger R2() {
|
||||
return R2(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right trigger 2 button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the right trigger 2 button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger R2(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kR2.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the create button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the create button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #create(EventLoop)
|
||||
*/
|
||||
public Trigger create() {
|
||||
return create(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the create button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the create button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger create(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kCreate.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the options button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the options button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #options(EventLoop)
|
||||
*/
|
||||
public Trigger options() {
|
||||
return options(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the options button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the options button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger options(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kOptions.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the L3 (left stick) button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the L3 (left stick) button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #L3(EventLoop)
|
||||
*/
|
||||
public Trigger L3() {
|
||||
return L3(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the L3 (left stick) button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the L3 (left stick) button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger L3(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kL3.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the R3 (right stick) button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the R3 (right stick) button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #R3(EventLoop)
|
||||
*/
|
||||
public Trigger R3() {
|
||||
return R3(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the R3 (right stick) button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the R3 (right stick) button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger R3(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kR3.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the PlayStation button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the PlayStation button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #PS(EventLoop)
|
||||
*/
|
||||
public Trigger PS() {
|
||||
return PS(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the PlayStation button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the PlayStation button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger PS(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kPS.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the touchpad button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the touchpad button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #touchpad(EventLoop)
|
||||
*/
|
||||
public Trigger touchpad() {
|
||||
return touchpad(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the touchpad button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the touchpad button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger touchpad(EventLoop loop) {
|
||||
return button(PS5Controller.Button.kTouchpad.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X axis value of left side of the controller. Right is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getLeftX() {
|
||||
return m_hid.getLeftX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y axis value of left side of the controller. Back is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getLeftY() {
|
||||
return m_hid.getLeftY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X axis value of right side of the controller. Right is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getRightX() {
|
||||
return m_hid.getRightX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y axis value of right side of the controller. Back is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getRightY() {
|
||||
return m_hid.getRightY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the left trigger 2 axis value of the controller. Note that this axis is bound to the
|
||||
* range of [0, 1] as opposed to the usual [-1, 1].
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getL2Axis() {
|
||||
return m_hid.getL2Axis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the right trigger 2 axis value of the controller. Note that this axis is bound to the
|
||||
* range of [0, 1] as opposed to the usual [-1, 1].
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getR2Axis() {
|
||||
return m_hid.getR2Axis();
|
||||
}
|
||||
}
|
||||
@@ -1,451 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
// THIS FILE WAS AUTO-GENERATED BY ./commandsv3/generate_files.py. DO NOT MODIFY
|
||||
|
||||
package org.wpilib.commands3.button;
|
||||
|
||||
import edu.wpi.first.wpilibj.StadiaController;
|
||||
import edu.wpi.first.wpilibj.event.EventLoop;
|
||||
import org.wpilib.commands3.Scheduler;
|
||||
import org.wpilib.commands3.Trigger;
|
||||
|
||||
/**
|
||||
* A version of {@link StadiaController} with {@link Trigger} factories for command-based.
|
||||
*
|
||||
* @see StadiaController
|
||||
*/
|
||||
@SuppressWarnings("MethodName")
|
||||
public class CommandStadiaController extends CommandGenericHID {
|
||||
private final StadiaController m_hid;
|
||||
|
||||
/**
|
||||
* Construct an instance of a controller. Commands bound to buttons on the controller will be
|
||||
* scheduled on the {@link Scheduler#getDefault() default scheduler} using its default event loop.
|
||||
*
|
||||
* @param port The port index on the Driver Station that the controller is plugged into.
|
||||
*/
|
||||
public CommandStadiaController(int port) {
|
||||
super(port);
|
||||
m_hid = new StadiaController(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance of a controller. Commands bound to buttons on the controller will be
|
||||
* scheduled on the given scheduler using its default event loop.
|
||||
*
|
||||
* @param scheduler The scheduler that should execute the triggered commands.
|
||||
* @param port The port index on the Driver Station that the controller is plugged into.
|
||||
*/
|
||||
public CommandStadiaController(Scheduler scheduler, int port) {
|
||||
super(scheduler, port);
|
||||
m_hid = new StadiaController(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying GenericHID object.
|
||||
*
|
||||
* @return the wrapped GenericHID object
|
||||
*/
|
||||
@Override
|
||||
public StadiaController getHID() {
|
||||
return m_hid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the A button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the A button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #a(EventLoop)
|
||||
*/
|
||||
public Trigger a() {
|
||||
return a(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the A button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the A button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger a(EventLoop loop) {
|
||||
return button(StadiaController.Button.kA.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the B button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the B button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #b(EventLoop)
|
||||
*/
|
||||
public Trigger b() {
|
||||
return b(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the B button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the B button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger b(EventLoop loop) {
|
||||
return button(StadiaController.Button.kB.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the X button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the X button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #x(EventLoop)
|
||||
*/
|
||||
public Trigger x() {
|
||||
return x(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the X button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the X button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger x(EventLoop loop) {
|
||||
return button(StadiaController.Button.kX.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the Y button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the Y button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #y(EventLoop)
|
||||
*/
|
||||
public Trigger y() {
|
||||
return y(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the Y button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the Y button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger y(EventLoop loop) {
|
||||
return button(StadiaController.Button.kY.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left bumper button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the left bumper button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #leftBumper(EventLoop)
|
||||
*/
|
||||
public Trigger leftBumper() {
|
||||
return leftBumper(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left bumper button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the left bumper button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger leftBumper(EventLoop loop) {
|
||||
return button(StadiaController.Button.kLeftBumper.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right bumper button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the right bumper button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #rightBumper(EventLoop)
|
||||
*/
|
||||
public Trigger rightBumper() {
|
||||
return rightBumper(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right bumper button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the right bumper button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger rightBumper(EventLoop loop) {
|
||||
return button(StadiaController.Button.kRightBumper.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left stick button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the left stick button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #leftStick(EventLoop)
|
||||
*/
|
||||
public Trigger leftStick() {
|
||||
return leftStick(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left stick button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the left stick button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger leftStick(EventLoop loop) {
|
||||
return button(StadiaController.Button.kLeftStick.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right stick button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the right stick button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #rightStick(EventLoop)
|
||||
*/
|
||||
public Trigger rightStick() {
|
||||
return rightStick(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right stick button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the right stick button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger rightStick(EventLoop loop) {
|
||||
return button(StadiaController.Button.kRightStick.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the ellipses button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the ellipses button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #ellipses(EventLoop)
|
||||
*/
|
||||
public Trigger ellipses() {
|
||||
return ellipses(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the ellipses button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the ellipses button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger ellipses(EventLoop loop) {
|
||||
return button(StadiaController.Button.kEllipses.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the hamburger button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the hamburger button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #hamburger(EventLoop)
|
||||
*/
|
||||
public Trigger hamburger() {
|
||||
return hamburger(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the hamburger button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the hamburger button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger hamburger(EventLoop loop) {
|
||||
return button(StadiaController.Button.kHamburger.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the stadia button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the stadia button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #stadia(EventLoop)
|
||||
*/
|
||||
public Trigger stadia() {
|
||||
return stadia(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the stadia button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the stadia button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger stadia(EventLoop loop) {
|
||||
return button(StadiaController.Button.kStadia.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right trigger button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the right trigger button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #rightTrigger(EventLoop)
|
||||
*/
|
||||
public Trigger rightTrigger() {
|
||||
return rightTrigger(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right trigger button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the right trigger button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger rightTrigger(EventLoop loop) {
|
||||
return button(StadiaController.Button.kRightTrigger.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left trigger button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the left trigger button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #leftTrigger(EventLoop)
|
||||
*/
|
||||
public Trigger leftTrigger() {
|
||||
return leftTrigger(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left trigger button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the left trigger button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger leftTrigger(EventLoop loop) {
|
||||
return button(StadiaController.Button.kLeftTrigger.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the google button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the google button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #google(EventLoop)
|
||||
*/
|
||||
public Trigger google() {
|
||||
return google(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the google button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the google button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger google(EventLoop loop) {
|
||||
return button(StadiaController.Button.kGoogle.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the frame button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the frame button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #frame(EventLoop)
|
||||
*/
|
||||
public Trigger frame() {
|
||||
return frame(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the frame button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the frame button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger frame(EventLoop loop) {
|
||||
return button(StadiaController.Button.kFrame.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X axis value of left side of the controller. Right is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getLeftX() {
|
||||
return m_hid.getLeftX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X axis value of right side of the controller. Right is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getRightX() {
|
||||
return m_hid.getRightX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y axis value of left side of the controller. Back is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getLeftY() {
|
||||
return m_hid.getLeftY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y axis value of right side of the controller. Back is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getRightY() {
|
||||
return m_hid.getRightY();
|
||||
}
|
||||
}
|
||||
@@ -1,435 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
// THIS FILE WAS AUTO-GENERATED BY ./commandsv3/generate_files.py. DO NOT MODIFY
|
||||
|
||||
package org.wpilib.commands3.button;
|
||||
|
||||
import edu.wpi.first.wpilibj.XboxController;
|
||||
import edu.wpi.first.wpilibj.event.EventLoop;
|
||||
import org.wpilib.commands3.Scheduler;
|
||||
import org.wpilib.commands3.Trigger;
|
||||
|
||||
/**
|
||||
* A version of {@link XboxController} with {@link Trigger} factories for command-based.
|
||||
*
|
||||
* @see XboxController
|
||||
*/
|
||||
@SuppressWarnings("MethodName")
|
||||
public class CommandXboxController extends CommandGenericHID {
|
||||
private final XboxController m_hid;
|
||||
|
||||
/**
|
||||
* Construct an instance of a controller. Commands bound to buttons on the controller will be
|
||||
* scheduled on the {@link Scheduler#getDefault() default scheduler} using its default event loop.
|
||||
*
|
||||
* @param port The port index on the Driver Station that the controller is plugged into.
|
||||
*/
|
||||
public CommandXboxController(int port) {
|
||||
super(port);
|
||||
m_hid = new XboxController(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance of a controller. Commands bound to buttons on the controller will be
|
||||
* scheduled on the given scheduler using its default event loop.
|
||||
*
|
||||
* @param scheduler The scheduler that should execute the triggered commands.
|
||||
* @param port The port index on the Driver Station that the controller is plugged into.
|
||||
*/
|
||||
public CommandXboxController(Scheduler scheduler, int port) {
|
||||
super(scheduler, port);
|
||||
m_hid = new XboxController(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying GenericHID object.
|
||||
*
|
||||
* @return the wrapped GenericHID object
|
||||
*/
|
||||
@Override
|
||||
public XboxController getHID() {
|
||||
return m_hid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the A button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the A button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #a(EventLoop)
|
||||
*/
|
||||
public Trigger a() {
|
||||
return a(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the A button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the A button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger a(EventLoop loop) {
|
||||
return button(XboxController.Button.kA.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the B button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the B button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #b(EventLoop)
|
||||
*/
|
||||
public Trigger b() {
|
||||
return b(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the B button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the B button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger b(EventLoop loop) {
|
||||
return button(XboxController.Button.kB.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the X button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the X button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #x(EventLoop)
|
||||
*/
|
||||
public Trigger x() {
|
||||
return x(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the X button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the X button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger x(EventLoop loop) {
|
||||
return button(XboxController.Button.kX.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the Y button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the Y button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #y(EventLoop)
|
||||
*/
|
||||
public Trigger y() {
|
||||
return y(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the Y button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the Y button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger y(EventLoop loop) {
|
||||
return button(XboxController.Button.kY.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left bumper button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the left bumper button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #leftBumper(EventLoop)
|
||||
*/
|
||||
public Trigger leftBumper() {
|
||||
return leftBumper(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left bumper button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the left bumper button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger leftBumper(EventLoop loop) {
|
||||
return button(XboxController.Button.kLeftBumper.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right bumper button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the right bumper button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #rightBumper(EventLoop)
|
||||
*/
|
||||
public Trigger rightBumper() {
|
||||
return rightBumper(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right bumper button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the right bumper button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger rightBumper(EventLoop loop) {
|
||||
return button(XboxController.Button.kRightBumper.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the back button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the back button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #back(EventLoop)
|
||||
*/
|
||||
public Trigger back() {
|
||||
return back(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the back button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the back button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger back(EventLoop loop) {
|
||||
return button(XboxController.Button.kBack.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the start button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the start button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #start(EventLoop)
|
||||
*/
|
||||
public Trigger start() {
|
||||
return start(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the start button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the start button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger start(EventLoop loop) {
|
||||
return button(XboxController.Button.kStart.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left stick button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the left stick button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #leftStick(EventLoop)
|
||||
*/
|
||||
public Trigger leftStick() {
|
||||
return leftStick(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the left stick button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the left stick button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger leftStick(EventLoop loop) {
|
||||
return button(XboxController.Button.kLeftStick.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right stick button's digital signal.
|
||||
*
|
||||
* @return a Trigger instance representing the right stick button's digital signal attached
|
||||
* to the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
* @see #rightStick(EventLoop)
|
||||
*/
|
||||
public Trigger rightStick() {
|
||||
return rightStick(getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the right stick button's digital signal.
|
||||
*
|
||||
* @param loop the event loop instance to attach the event to.
|
||||
* @return a Trigger instance representing the right stick button's digital signal attached
|
||||
* to the given loop.
|
||||
*/
|
||||
public Trigger rightStick(EventLoop loop) {
|
||||
return button(XboxController.Button.kRightStick.value, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the axis value of the left trigger. The returned
|
||||
* trigger will be true when the axis value is greater than {@code threshold}.
|
||||
*
|
||||
* @param threshold the minimum axis value for the returned {@link Trigger} to be true. This value
|
||||
* should be in the range [0, 1] where 0 is the unpressed state of the axis.
|
||||
* @param loop the event loop instance to attach the Trigger to.
|
||||
* @return a Trigger instance that is true when the left trigger's axis exceeds the provided
|
||||
* threshold, attached to the given event loop
|
||||
*/
|
||||
public Trigger leftTrigger(double threshold, EventLoop loop) {
|
||||
return axisGreaterThan(XboxController.Axis.kLeftTrigger.value, threshold, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the axis value of the left trigger. The returned
|
||||
* trigger will be true when the axis value is greater than {@code threshold}.
|
||||
*
|
||||
* @param threshold the minimum axis value for the returned {@link Trigger} to be true. This value
|
||||
* should be in the range [0, 1] where 0 is the unpressed state of the axis.
|
||||
* @return a Trigger instance that is true when the left trigger's axis exceeds the provided
|
||||
* threshold, attached to the {@link Scheduler#getDefaultEventLoop() default scheduler event
|
||||
* loop} on the scheduler passed to the controller's constructor, or the {@link
|
||||
* Scheduler#getDefault default scheduler} if a scheduler was not explicitly provided.
|
||||
*/
|
||||
public Trigger leftTrigger(double threshold) {
|
||||
return leftTrigger(threshold, getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the axis value of the left trigger. The returned trigger
|
||||
* will be true when the axis value is greater than 0.5.
|
||||
*
|
||||
* @return a Trigger instance that is true when the left trigger's axis exceeds 0.5, attached to
|
||||
* the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
*/
|
||||
public Trigger leftTrigger() {
|
||||
return leftTrigger(0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the axis value of the right trigger. The returned
|
||||
* trigger will be true when the axis value is greater than {@code threshold}.
|
||||
*
|
||||
* @param threshold the minimum axis value for the returned {@link Trigger} to be true. This value
|
||||
* should be in the range [0, 1] where 0 is the unpressed state of the axis.
|
||||
* @param loop the event loop instance to attach the Trigger to.
|
||||
* @return a Trigger instance that is true when the right trigger's axis exceeds the provided
|
||||
* threshold, attached to the given event loop
|
||||
*/
|
||||
public Trigger rightTrigger(double threshold, EventLoop loop) {
|
||||
return axisGreaterThan(XboxController.Axis.kRightTrigger.value, threshold, loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the axis value of the right trigger. The returned
|
||||
* trigger will be true when the axis value is greater than {@code threshold}.
|
||||
*
|
||||
* @param threshold the minimum axis value for the returned {@link Trigger} to be true. This value
|
||||
* should be in the range [0, 1] where 0 is the unpressed state of the axis.
|
||||
* @return a Trigger instance that is true when the right trigger's axis exceeds the provided
|
||||
* threshold, attached to the {@link Scheduler#getDefaultEventLoop() default scheduler event
|
||||
* loop} on the scheduler passed to the controller's constructor, or the {@link
|
||||
* Scheduler#getDefault default scheduler} if a scheduler was not explicitly provided.
|
||||
*/
|
||||
public Trigger rightTrigger(double threshold) {
|
||||
return rightTrigger(threshold, getScheduler().getDefaultEventLoop());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Trigger instance around the axis value of the right trigger. The returned trigger
|
||||
* will be true when the axis value is greater than 0.5.
|
||||
*
|
||||
* @return a Trigger instance that is true when the right trigger's axis exceeds 0.5, attached to
|
||||
* the {@link Scheduler#getDefaultEventLoop() default scheduler event loop} on the
|
||||
* scheduler passed to the controller's constructor, or the {@link Scheduler#getDefault
|
||||
* default scheduler} if a scheduler was not explicitly provided.
|
||||
*/
|
||||
public Trigger rightTrigger() {
|
||||
return rightTrigger(0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X axis value of left side of the controller. Right is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getLeftX() {
|
||||
return m_hid.getLeftX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X axis value of right side of the controller. Right is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getRightX() {
|
||||
return m_hid.getRightX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y axis value of left side of the controller. Back is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getLeftY() {
|
||||
return m_hid.getLeftY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y axis value of right side of the controller. Back is positive.
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getRightY() {
|
||||
return m_hid.getRightY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the left trigger axis value of the controller. Note that this axis is bound to the
|
||||
* range of [0, 1] as opposed to the usual [-1, 1].
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getLeftTriggerAxis() {
|
||||
return m_hid.getLeftTriggerAxis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the right trigger axis value of the controller. Note that this axis is bound to the
|
||||
* range of [0, 1] as opposed to the usual [-1, 1].
|
||||
*
|
||||
* @return The axis value.
|
||||
*/
|
||||
public double getRightTriggerAxis() {
|
||||
return m_hid.getRightTriggerAxis();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
import edu.wpi.first.util.ErrorMessages;
|
||||
|
||||
/**
|
||||
* A single trigger binding.
|
||||
*
|
||||
* @param scope The scope in which the binding is active.
|
||||
* @param type The type of binding; or, when the bound command should run
|
||||
* @param command The bound command. Cannot be null.
|
||||
* @param frames The stack frames when the binding was created. Used for telemetry and error
|
||||
* reporting so if a command throws an exception, we can tell users where that command was bound
|
||||
* instead of giving a fairly useless backtrace of the command framework.
|
||||
*/
|
||||
record Binding(BindingScope scope, BindingType type, Command command, StackTraceElement[] frames) {
|
||||
public Binding {
|
||||
ErrorMessages.requireNonNullParam(scope, "scope", "Binding");
|
||||
ErrorMessages.requireNonNullParam(type, "type", "Binding");
|
||||
ErrorMessages.requireNonNullParam(command, "command", "Binding");
|
||||
ErrorMessages.requireNonNullParam(frames, "frames", "Binding");
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
/**
|
||||
* A scope for when a binding is live. Bindings tied to a scope must be deleted when the scope
|
||||
* becomes inactive.
|
||||
*/
|
||||
@SuppressWarnings("PMD.ImplicitFunctionalInterface")
|
||||
interface BindingScope {
|
||||
/**
|
||||
* Checks if the scope is active. Bindings for inactive scopes are removed from the scheduler.
|
||||
*
|
||||
* @return True if the scope is still active, false if not.
|
||||
*/
|
||||
boolean active();
|
||||
|
||||
static BindingScope global() {
|
||||
return Global.INSTANCE;
|
||||
}
|
||||
|
||||
static BindingScope forCommand(Scheduler scheduler, Command command) {
|
||||
return new ForCommand(scheduler, command);
|
||||
}
|
||||
|
||||
/** A global binding scope. Bindings in this scope are always active. */
|
||||
final class Global implements BindingScope {
|
||||
// No reason not to be a singleton.
|
||||
public static final Global INSTANCE = new Global();
|
||||
|
||||
@Override
|
||||
public boolean active() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A binding scoped to the lifetime of a specific command. This should be used when a binding is
|
||||
* created within a command, tying the lifetime of the binding to the declaring command.
|
||||
*
|
||||
* @param scheduler The scheduler managing the command.
|
||||
* @param command The command being scoped to.
|
||||
*/
|
||||
record ForCommand(Scheduler scheduler, Command command) implements BindingScope {
|
||||
@Override
|
||||
public boolean active() {
|
||||
return scheduler.isRunning(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
/** Describes when a command bound to a trigger should run. */
|
||||
enum BindingType {
|
||||
/**
|
||||
* An immediate or manual binding created when calling {@link Scheduler#schedule(Command)}
|
||||
* directly, without using a trigger to bind it to a signal.
|
||||
*/
|
||||
IMMEDIATE,
|
||||
/**
|
||||
* Schedules (forks) a command on a rising edge signal. The command will run until it completes or
|
||||
* is interrupted by another command requiring the same mechanisms.
|
||||
*/
|
||||
SCHEDULE_ON_RISING_EDGE,
|
||||
/**
|
||||
* Schedules (forks) a command on a falling edge signal. The command will run until it completes
|
||||
* or is interrupted by another command requiring the same mechanisms.
|
||||
*/
|
||||
SCHEDULE_ON_FALLING_EDGE,
|
||||
/**
|
||||
* Schedules (forks) a command on a rising edge signal. If the command is still running on the
|
||||
* next rising edge, it will be canceled then; otherwise, it will be scheduled again.
|
||||
*/
|
||||
TOGGLE_ON_RISING_EDGE,
|
||||
/**
|
||||
* Schedules (forks) a command on a falling edge signal. If the command is still running on the
|
||||
* next falling edge, it will be canceled then; otherwise, it will be scheduled again.
|
||||
*/
|
||||
TOGGLE_ON_FALLING_EDGE,
|
||||
/**
|
||||
* Schedules a command on a rising edge signal. If the command is still running on the next
|
||||
* falling edge, it will be canceled then - unlike {@link #SCHEDULE_ON_RISING_EDGE}, which would
|
||||
* allow it to continue to run.
|
||||
*/
|
||||
RUN_WHILE_HIGH,
|
||||
/**
|
||||
* Schedules a command on a falling edge signal. If the command is still running on the next
|
||||
* rising edge, it will be canceled then - unlike {@link #SCHEDULE_ON_FALLING_EDGE}, which would
|
||||
* allow it to continue to run.
|
||||
*/
|
||||
RUN_WHILE_LOW
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
|
||||
|
||||
import edu.wpi.first.units.measure.Time;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
import org.wpilib.annotation.NoDiscard;
|
||||
|
||||
/**
|
||||
* Performs some task using one or more {@link Mechanism mechanisms}. Commands are fundamentally
|
||||
* backed by a {@link Coroutine} that can be used to write imperative code that runs asynchronously.
|
||||
*
|
||||
* <p>Programmers familiar with the earlier versions of the command framework can think of a v3
|
||||
* command similar to a v1 or v2 command that executes the lifecycle methods in a single method, as
|
||||
* demonstrated in the example below. (Note, however, that more sophisticated code than this is
|
||||
* possible!
|
||||
*
|
||||
* <pre>{@code
|
||||
* coroutine -> {
|
||||
* initialize();
|
||||
* while (!isFinished()) {
|
||||
* execute();
|
||||
* coroutine.yield(); // be sure to yield at the end of the loop
|
||||
* }
|
||||
* end();
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p><strong>Note:</strong> Because coroutines are <i>opt-in</i> collaborate constructs, every
|
||||
* command implementation <strong>must</strong> call {@link Coroutine#yield()} within any periodic
|
||||
* loop. Failure to do so may result in an unrecoverable infinite loop.
|
||||
*
|
||||
* <h2>Requirements</h2>
|
||||
*
|
||||
* <p>Commands require zero or more mechanisms. To prevent conflicting control requests from running
|
||||
* simultaneously (for example, commanding an elevator to both raise and lower at the same time), a
|
||||
* running command has <i>exclusive ownership</i> of all of its required mechanisms. If another
|
||||
* command with an equal or greater {@link #priority()} is scheduled that requires one or more of
|
||||
* those same mechanisms, it will interrupt and cancel the running command.
|
||||
*
|
||||
* <p>The recommended way to create a command is using {@link Mechanism#run(Consumer)} or a related
|
||||
* factory method to create commands that require a single mechanism (for example, a command that
|
||||
* drives an elevator up and down or rotates an arm). Commands may be <i>composed</i> into {@link
|
||||
* ParallelGroup parallel groups} and {@link SequentialGroup sequences} to build more complex
|
||||
* behavior out of fundamental building blocks. These built-in compositions will require every
|
||||
* mechanism used by every command in them, even if those commands aren't always running, and thus
|
||||
* can leave certain required mechanisms in an <i>uncommanded</i> state: owned, but not used, this
|
||||
* can lead to mechanisms sagging under gravity or running the previous motor control request they
|
||||
* were given.
|
||||
*
|
||||
* <h2>Advanced Usage</h2>
|
||||
*
|
||||
* <p>For example, a hypothetical drive-and-score sequence could be coded in two ways: one with a
|
||||
* sequence chain, or one that uses the lower-level coroutine API. Coroutines can be used in an
|
||||
* async/await style that you may be familiar with from languages like JavaScript, Python, or C#
|
||||
* (note that there is no {@code async} keyword; commands are inherently asynchronous). Nested
|
||||
* commands may be forked and awaited, but will not outlive the command that forked them; there is
|
||||
* no analog for something like a {@code ScheduleCommand} from the v2 commands framework.
|
||||
*
|
||||
* <pre>{@code
|
||||
* class Robot extends TimedRobot {
|
||||
* private final Drivetrain drivetrain = new Drivetrain();
|
||||
* private final Elevator elevator = new Elevator();
|
||||
* private final Gripper gripper = new Gripper();
|
||||
*
|
||||
* // Basic sequence builder - owns all 3 mechanisms for the full duration,
|
||||
* // even when they're not being used
|
||||
* private Command basicScoringSequence() {
|
||||
* return drivetrain.driveToScoringLocation()
|
||||
* .andThen(elevator.moveToScoringHeight())
|
||||
* .andThen(gripper.release())
|
||||
* .named("Scoring Sequence (Basic)");
|
||||
* }
|
||||
*
|
||||
* // Advanced sequence with async/await - only owns mechanisms while they're
|
||||
* // being used, allowing default commands or other user-triggered commands
|
||||
* // to run when not in use. Interrupting one of the inner commands while it's
|
||||
* // running will cancel the entire sequence.
|
||||
* private Command advancedScoringSequence() {
|
||||
* return Command.noRequirements().executing(coroutine -> {
|
||||
* coroutine.await(drivetrain.driveToScoringLocation());
|
||||
* coroutine.await(elevator.moveToScoringHeight());
|
||||
* coroutine.await(gripper.release());
|
||||
* }).named("Scoring Sequence (Advanced)");
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
@NoDiscard("Commands must be used! Did you mean to fork it or bind it to a trigger?")
|
||||
public interface Command {
|
||||
/** The default command priority. */
|
||||
int DEFAULT_PRIORITY = 0;
|
||||
|
||||
/**
|
||||
* The lowest possible command priority. Commands with the lowest priority can be interrupted by
|
||||
* any other command, including other minimum-priority commands.
|
||||
*/
|
||||
int LOWEST_PRIORITY = Integer.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* The highest possible command priority. Commands with the highest priority can only be
|
||||
* interrupted by other maximum-priority commands.
|
||||
*/
|
||||
int HIGHEST_PRIORITY = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Runs the command. Commands that need to periodically run until a goal state is reached should
|
||||
* simply run a while loop like {@code while (!atGoal()) { ... } } and call {@link
|
||||
* Coroutine#yield()} at the end of the loop.
|
||||
*
|
||||
* <p><strong>Warning:</strong> any loops in a command must call {@code coroutine.yield()}.
|
||||
* Failure to do so will prevent anything else in your robot code from running. Commands are
|
||||
* <i>opt-in</i> collaborative constructs; don't be greedy!
|
||||
*
|
||||
* @param coroutine the coroutine backing the command's execution
|
||||
*/
|
||||
void run(Coroutine coroutine);
|
||||
|
||||
/**
|
||||
* An optional lifecycle hook that can be implemented to execute some code whenever this command
|
||||
* is canceled before it naturally completes. Commands should be careful to do a single-shot
|
||||
* cleanup (for example, setting a motor to zero volts) and not do any complex looping logic here.
|
||||
*/
|
||||
default void onCancel() {
|
||||
// NOP by default
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the command.
|
||||
*
|
||||
* @return the name of the command
|
||||
*/
|
||||
@NoDiscard
|
||||
String name();
|
||||
|
||||
/**
|
||||
* The mechanisms required by the command. This is used by the scheduler to determine if two
|
||||
* commands conflict with each other. No mechanism may be required by more than one running
|
||||
* command at a time.
|
||||
*
|
||||
* @return the set of mechanisms required by the command
|
||||
*/
|
||||
@NoDiscard
|
||||
Set<Mechanism> requirements();
|
||||
|
||||
/**
|
||||
* The priority of the command. If a command is scheduled that conflicts with another running or
|
||||
* pending command, their priority values are compared to determine which should run. If the
|
||||
* scheduled command is lower priority than the running command, then it will not be scheduled and
|
||||
* the running command will continue to run. If it is the same or higher priority, then the
|
||||
* running command will be canceled and the scheduled command will start to run.
|
||||
*
|
||||
* @return the priority of the command
|
||||
*/
|
||||
@NoDiscard
|
||||
default int priority() {
|
||||
return DEFAULT_PRIORITY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this command has a lower {@link #priority() priority} than another command.
|
||||
*
|
||||
* @param other the command to compare with
|
||||
* @return true if this command has a lower priority than the other one, false otherwise
|
||||
*/
|
||||
@NoDiscard
|
||||
default boolean isLowerPriorityThan(Command other) {
|
||||
requireNonNullParam(other, "other", "Command.isLowerPriorityThan");
|
||||
|
||||
return priority() < other.priority();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this command requires a particular mechanism.
|
||||
*
|
||||
* @param mechanism the mechanism to check
|
||||
* @return true if the mechanism is required, false if not
|
||||
*/
|
||||
@NoDiscard
|
||||
default boolean requires(Mechanism mechanism) {
|
||||
return requirements().contains(mechanism);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this command conflicts with another command.
|
||||
*
|
||||
* @param other the commands to check against
|
||||
* @return true if both commands require at least one of the same mechanism, false if both
|
||||
* commands have completely different requirements
|
||||
*/
|
||||
@NoDiscard
|
||||
default boolean conflictsWith(Command other) {
|
||||
requireNonNullParam(other, "other", "Command.conflictsWith");
|
||||
|
||||
return !Collections.disjoint(requirements(), other.requirements());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new command that runs this one for a maximum duration, after which it is forcibly
|
||||
* canceled. This is particularly useful for autonomous routines where you want to prevent your
|
||||
* entire autonomous period spent stuck on a single action because a mechanism doesn't quite reach
|
||||
* its setpoint (for example, spinning up a flywheel or driving to a particular location on the
|
||||
* field). The resulting command will have the same name as this one, with the timeout period
|
||||
* appended.
|
||||
*
|
||||
* @param timeout the maximum duration that the command is permitted to run. Negative or zero
|
||||
* values will result in the command running only once before being canceled.
|
||||
* @return the timed out command.
|
||||
*/
|
||||
default Command withTimeout(Time timeout) {
|
||||
requireNonNullParam(timeout, "timeout", "Command.withTimeout");
|
||||
|
||||
return race(this, waitFor(timeout).named("Timeout: " + timeout.toLongString()))
|
||||
.named(name() + " [" + timeout.toLongString() + " timeout]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a command that does not require any hardware; that is, it does not affect the state of
|
||||
* any physical objects. This is useful for commands that do some cleanup or state management,
|
||||
* such as resetting odometry or sensors, that you don't want to interrupt a command that's
|
||||
* controlling the mechanisms it affects.
|
||||
*
|
||||
* <p>More configuration options are needed after calling this function before the command can be
|
||||
* created. See {@link StagedCommandBuilder} for details.
|
||||
*
|
||||
* @return a builder that can be used to configure the resulting command
|
||||
*/
|
||||
static NeedsExecutionBuilderStage noRequirements() {
|
||||
return new StagedCommandBuilder().noRequirements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a command that requires one or more mechanisms.
|
||||
*
|
||||
* <p>More configuration options are needed after calling this function before the command can be
|
||||
* created. See {@link StagedCommandBuilder} for details.
|
||||
*
|
||||
* @param requirement The first required mechanism
|
||||
* @param rest Any other required mechanisms
|
||||
* @return A command builder
|
||||
*/
|
||||
static NeedsExecutionBuilderStage requiring(Mechanism requirement, Mechanism... rest) {
|
||||
// parameters will be null checked by the builder
|
||||
return new StagedCommandBuilder().requiring(requirement, rest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates command that requires some number of mechanisms.
|
||||
*
|
||||
* <p>More configuration options are needed after calling this function before the command can be
|
||||
* created. See {@link StagedCommandBuilder} for details.
|
||||
*
|
||||
* @param requirements The required mechanisms. May be empty, but cannot contain null values.
|
||||
* @return A command builder
|
||||
*/
|
||||
static NeedsExecutionBuilderStage requiring(Collection<Mechanism> requirements) {
|
||||
// parameters will be null checked by the builder
|
||||
return new StagedCommandBuilder().requiring(requirements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts creating a command that runs a group of multiple commands in parallel. The command will
|
||||
* complete when every command in the group has completed naturally.
|
||||
*
|
||||
* <p>More configuration options are needed after calling this function before the command can be
|
||||
* created. See {@link ParallelGroupBuilder} for details.
|
||||
*
|
||||
* @param commands The commands to run in parallel
|
||||
* @return A command builder
|
||||
*/
|
||||
static ParallelGroupBuilder parallel(Command... commands) {
|
||||
// parameters will be null checked by the builder
|
||||
return new ParallelGroupBuilder().requiring(commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts creating a command that runs a group of multiple commands in parallel. The command will
|
||||
* complete when any command in the group has completed naturally; all other commands in the group
|
||||
* will be canceled.
|
||||
*
|
||||
* <p>More configuration options are needed after calling this function before the command can be
|
||||
* created. See {@link ParallelGroupBuilder} for details.
|
||||
*
|
||||
* @param commands The commands to run in parallel
|
||||
* @return A command builder
|
||||
*/
|
||||
static ParallelGroupBuilder race(Command... commands) {
|
||||
// parameters will be null checked by the builder
|
||||
return new ParallelGroupBuilder().optional(commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts creating a command that runs a group of multiple commands in sequence. The command will
|
||||
* complete when the last command in the group has completed naturally. Commands in the group will
|
||||
* run in the order they're passed to this method.
|
||||
*
|
||||
* <p>More configuration options are needed after calling this function before the command can be
|
||||
* created. See {@link SequentialGroupBuilder} for details.
|
||||
*
|
||||
* @param commands The commands to run in sequence.
|
||||
* @return A command builder
|
||||
*/
|
||||
static SequentialGroupBuilder sequence(Command... commands) {
|
||||
// parameters will be null checked by the builder
|
||||
return new SequentialGroupBuilder().andThen(commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts creating a command that simply waits for some condition to be met. The command will not
|
||||
* require any mechanisms.
|
||||
*
|
||||
* <p>More configuration options are needed after calling this function before the command can be
|
||||
* created. See {@link StagedCommandBuilder} for details.
|
||||
*
|
||||
* @param condition The condition to wait for
|
||||
* @return A command builder
|
||||
*/
|
||||
static NeedsNameBuilderStage waitUntil(BooleanSupplier condition) {
|
||||
requireNonNullParam(condition, "condition", "Command.waitUntil");
|
||||
|
||||
return noRequirements().executing(coroutine -> coroutine.waitUntil(condition));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a command that simply waits for a given duration. The command will not require any
|
||||
* mechanisms.
|
||||
*
|
||||
* @param duration How long to wait
|
||||
* @return A command builder
|
||||
*/
|
||||
static NeedsNameBuilderStage waitFor(Time duration) {
|
||||
requireNonNullParam(duration, "duration", "Command.waitFor");
|
||||
|
||||
return noRequirements().executing(coroutine -> coroutine.wait(duration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a command that runs this one and ends when the end condition is met (if this command
|
||||
* has not already exited by then).
|
||||
*
|
||||
* <p>More configuration options are needed after calling this function before the command can be
|
||||
* created. See {@link ParallelGroupBuilder} for details.
|
||||
*
|
||||
* @param endCondition The end condition to wait for.
|
||||
* @return The waiting command
|
||||
*/
|
||||
default ParallelGroupBuilder until(BooleanSupplier endCondition) {
|
||||
requireNonNullParam(endCondition, "endCondition", "Command.until");
|
||||
|
||||
return new ParallelGroupBuilder()
|
||||
.optional(this, Command.waitUntil(endCondition).named("Until Condition"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a command sequence, starting from this command and then running the next one. More
|
||||
* commands can be added with the builder before naming and creating the sequence.
|
||||
*
|
||||
* <pre>{@code
|
||||
* Sequence aThenBThenC =
|
||||
* commandA()
|
||||
* .andThen(commandB())
|
||||
* .andThen(commandC())
|
||||
* .withAutomaticName();
|
||||
* }</pre>
|
||||
*
|
||||
* @param next The command to run after this one in the sequence
|
||||
* @return A sequence builder
|
||||
*/
|
||||
default SequentialGroupBuilder andThen(Command next) {
|
||||
// parameter will be null checked by the builder
|
||||
return new SequentialGroupBuilder().andThen(this).andThen(next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a parallel command group, running this command alongside one or more other commands.
|
||||
* The group will exit once every command has finished.
|
||||
*
|
||||
* <p>More configuration options are needed after calling this function before the command can be
|
||||
* created. See {@link ParallelGroupBuilder} for details.
|
||||
*
|
||||
* <pre>{@code
|
||||
* ParallelGroup abc =
|
||||
* commandA()
|
||||
* .alongWith(commandB(), commandC())
|
||||
* .withAutomaticName();
|
||||
* }</pre>
|
||||
*
|
||||
* @param parallel The commands to run in parallel with this one
|
||||
* @return A parallel group builder
|
||||
*/
|
||||
default ParallelGroupBuilder alongWith(Command... parallel) {
|
||||
return new ParallelGroupBuilder().requiring(this).requiring(parallel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a parallel command group, running this command alongside one or more other commands.
|
||||
* The group will exit after any command finishes.
|
||||
*
|
||||
* <p>More configuration options are needed after calling this function before the command can be
|
||||
* created. See {@link ParallelGroupBuilder} for details.
|
||||
*
|
||||
* @param parallel The commands to run in parallel with this one
|
||||
* @return A parallel group builder
|
||||
*/
|
||||
default ParallelGroupBuilder raceWith(Command... parallel) {
|
||||
return new ParallelGroupBuilder().optional(this).optional(parallel);
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/** Represents the state of a command as it is executed by the scheduler. */
|
||||
final class CommandState {
|
||||
// Two billion unique IDs should be enough for anybody.
|
||||
private static int s_lastId = 0;
|
||||
|
||||
private final Command m_command;
|
||||
private final Command m_parent;
|
||||
private final Coroutine m_coroutine;
|
||||
private final Binding m_binding;
|
||||
private double m_lastRuntimeMs = -1;
|
||||
private double m_totalRuntimeMs;
|
||||
private final int m_id;
|
||||
|
||||
/**
|
||||
* Creates a new command state object.
|
||||
*
|
||||
* @param command The command being tracked.
|
||||
* @param parent The parent command composition that scheduled the tracked command. Null if the
|
||||
* command was scheduled by a top level construct like trigger bindings or manually scheduled
|
||||
* by a user. For deeply nested compositions, this tracks the <i>direct parent command</i>
|
||||
* that invoked the schedule() call; in this manner, an ancestry tree can be built, where each
|
||||
* {@code CommandState} object references a parent node in the tree.
|
||||
* @param coroutine The coroutine to which the command is bound.
|
||||
* @param binding The binding that caused the command to be scheduled.
|
||||
*/
|
||||
CommandState(Command command, Command parent, Coroutine coroutine, Binding binding) {
|
||||
m_command = requireNonNull(command, "WPILib bug: command state given null command");
|
||||
m_parent = parent; // allowed to be null
|
||||
m_coroutine = requireNonNull(coroutine, "WPILib bug: command state given null coroutine");
|
||||
m_binding = requireNonNull(binding, "WPILib bug: command state given null binding");
|
||||
|
||||
// This is incredibly non-thread safe, but nobody should be using the command framework across
|
||||
// multiple threads anyway. Worst case scenario, we'll get duplicate IDs for commands scheduled
|
||||
// by different threads and cause bad telemetry data without affecting program correctness.
|
||||
m_id = ++s_lastId;
|
||||
}
|
||||
|
||||
public Command command() {
|
||||
return m_command;
|
||||
}
|
||||
|
||||
public Command parent() {
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
public Coroutine coroutine() {
|
||||
return m_coroutine;
|
||||
}
|
||||
|
||||
public Binding binding() {
|
||||
return m_binding;
|
||||
}
|
||||
|
||||
/**
|
||||
* How long the command took to run the last time it executed. Defaults to -1 if the command has
|
||||
* not run at least once.
|
||||
*
|
||||
* @return The runtime, in milliseconds.
|
||||
*/
|
||||
public double lastRuntimeMs() {
|
||||
return m_lastRuntimeMs;
|
||||
}
|
||||
|
||||
public void setLastRuntimeMs(double lastRuntimeMs) {
|
||||
m_lastRuntimeMs = lastRuntimeMs;
|
||||
m_totalRuntimeMs += lastRuntimeMs;
|
||||
}
|
||||
|
||||
public double totalRuntimeMs() {
|
||||
return m_totalRuntimeMs;
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof CommandState that && m_id == that.m_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CommandState[command=%s, parent=%s, coroutine=%s, id=%d]"
|
||||
.formatted(m_command, m_parent, m_coroutine, m_id);
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
final class CommandTraceHelper {
|
||||
private CommandTraceHelper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a modified stack trace where the trace of the scheduling code replaces the trace of the
|
||||
* internal scheduler logic.
|
||||
*
|
||||
* @param commandExceptionTrace The trace of the exception raised during command execution.
|
||||
* @param commandScheduleTrace The trace of when the command was scheduled.
|
||||
* @return A new array of stack trace elements.
|
||||
*/
|
||||
public static StackTraceElement[] modifyTrace(
|
||||
StackTraceElement[] commandExceptionTrace, StackTraceElement[] commandScheduleTrace) {
|
||||
List<StackTraceElement> frames = new ArrayList<>();
|
||||
|
||||
List<String> filteredClasses =
|
||||
List.of(
|
||||
Coroutine.class.getName(),
|
||||
Continuation.class.getName(),
|
||||
Scheduler.class.getName(),
|
||||
"org.wpilib.commands3.StagedCommandBuilder$BuilderBackedCommand",
|
||||
"jdk.internal.vm.Continuation");
|
||||
|
||||
boolean sawRun = false;
|
||||
for (var exceptionFrame : commandExceptionTrace) {
|
||||
if (!filteredClasses.contains(exceptionFrame.getClassName())) {
|
||||
frames.add(exceptionFrame);
|
||||
}
|
||||
|
||||
// Inject the schedule trace immediately after the line of user code that called Scheduler.run
|
||||
if (sawRun) {
|
||||
// Inject a marker frame just so there's a distinction between the command's code and the
|
||||
// code that scheduled it, since they occur asynchronously
|
||||
frames.add(new StackTraceElement("=== Command Binding Trace ===", "", "", -1));
|
||||
|
||||
// Drop internal trigger frames, since they're not helpful for users.
|
||||
// The first frame here should be the line of user code that bound the command to a trigger.
|
||||
Stream.of(commandScheduleTrace)
|
||||
.dropWhile(
|
||||
frame -> {
|
||||
boolean inTriggerInternals = frame.getClassName().equals(Trigger.class.getName());
|
||||
boolean isScheduleCall =
|
||||
frame.getClassName().equals(Scheduler.class.getName())
|
||||
&& "schedule".equals(frame.getMethodName());
|
||||
|
||||
return inTriggerInternals || isScheduleCall;
|
||||
})
|
||||
.filter(frame -> !filteredClasses.contains(frame.getClassName()))
|
||||
.forEach(frames::add);
|
||||
break;
|
||||
}
|
||||
|
||||
if (exceptionFrame.getClassName().equals(Scheduler.class.getName())
|
||||
&& "run".equals(exceptionFrame.getMethodName())) {
|
||||
sawRun = true;
|
||||
}
|
||||
}
|
||||
|
||||
return frames.toArray(StackTraceElement[]::new);
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** Utility class for helping with detecting conflicts between commands. */
|
||||
public final class ConflictDetector {
|
||||
private ConflictDetector() {
|
||||
// This is a utility class!
|
||||
}
|
||||
|
||||
/**
|
||||
* A conflict between two commands.
|
||||
*
|
||||
* @param a The first conflicting command.
|
||||
* @param b The second conflicting command.
|
||||
* @param sharedRequirements The set of mechanisms required by both commands. This set is
|
||||
* read-only
|
||||
*/
|
||||
public record Conflict(Command a, Command b, Set<Mechanism> sharedRequirements) {
|
||||
/**
|
||||
* Gets a descriptive message for the conflict. The description includes the names of the
|
||||
* conflicting commands and the names of all mechanisms required by both commands.
|
||||
*
|
||||
* @return A description of the conflict.
|
||||
*/
|
||||
public String description() {
|
||||
var shared =
|
||||
sharedRequirements.stream()
|
||||
.map(Mechanism::getName)
|
||||
.sorted()
|
||||
.collect(Collectors.joining(", "));
|
||||
return "%s and %s both require %s".formatted(a.name(), b.name(), shared);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a set of commands have no internal requirement conflicts. An error is thrown if
|
||||
* a conflict is detected.
|
||||
*
|
||||
* @param commands The commands to validate
|
||||
* @throws IllegalArgumentException If at least one pair of commands is found in the input where
|
||||
* both commands have at least one required mechanism in common
|
||||
*/
|
||||
public static void throwIfConflicts(Collection<? extends Command> commands) {
|
||||
requireNonNullParam(commands, "commands", "ConflictDetector.throwIfConflicts");
|
||||
|
||||
var conflicts = findAllConflicts(commands);
|
||||
if (conflicts.isEmpty()) {
|
||||
// No conflicts, all good
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder message =
|
||||
new StringBuilder("Commands running in parallel cannot share requirements: ");
|
||||
for (int i = 0; i < conflicts.size(); i++) {
|
||||
Conflict conflict = conflicts.get(i);
|
||||
message.append(conflict.description());
|
||||
if (i < conflicts.size() - 1) {
|
||||
message.append("; ");
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(message.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all conflicting pairs of commands in the input collection.
|
||||
*
|
||||
* @param commands The commands to check.
|
||||
* @return All detected conflicts. The returned list is empty if no conflicts were found.
|
||||
*/
|
||||
@SuppressWarnings("PMD.CompareObjectsWithEquals")
|
||||
public static List<Conflict> findAllConflicts(Collection<? extends Command> commands) {
|
||||
requireNonNullParam(commands, "commands", "ConflictDetector.findAllConflicts");
|
||||
|
||||
List<Conflict> conflicts = new ArrayList<>();
|
||||
|
||||
int i = 0;
|
||||
for (Command command : commands) {
|
||||
i++;
|
||||
int j = 0;
|
||||
for (Command other : commands) {
|
||||
j++;
|
||||
if (j <= i) {
|
||||
// Skip all elements in 0..i so the inner loop only checks elements from i + 1 onward.
|
||||
// Ordering of the elements in the pair doesn't matter, and this prevents finding every
|
||||
// pair twice eg (A, B) and (B, A).
|
||||
continue;
|
||||
}
|
||||
|
||||
if (command == other) {
|
||||
// Commands cannot conflict with themselves, so just in case the input collection happens
|
||||
// to have duplicate elements we just skip any pairs of a command with itself.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (command.conflictsWith(other)) {
|
||||
conflicts.add(findConflict(command, other));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
private static Conflict findConflict(Command a, Command b) {
|
||||
Set<Mechanism> sharedRequirements = new HashSet<>(a.requirements());
|
||||
sharedRequirements.retainAll(b.requirements());
|
||||
return new Conflict(a, b, Set.copyOf(sharedRequirements));
|
||||
}
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
|
||||
/**
|
||||
* A wrapper around the JDK internal Continuation class. Continuations are one-shot (i.e., not
|
||||
* reusable after completion) and allow stack frames to be paused and resumed at a later time. They
|
||||
* are the underpinning for virtual threads, which have their own scheduler and JVM support. Bare
|
||||
* continuations are designed for internal use by the JVM; we have forcibly opened access to them
|
||||
* for use by the commands framework due to limitations of virtual threads; notably, their complete
|
||||
* lack of determinism and timing, which are critically important for real-time systems like robots.
|
||||
*
|
||||
* <p><strong>ONLY USE CONTINUATIONS IN A SINGLE THREADED CONTEXT.</strong> The JVM and JIT
|
||||
* compilers make fundamental assumptions about how continuations are used, and rely on the code
|
||||
* that uses it (which was intended to be virtual threads) to use it safely. <strong>Failure to use
|
||||
* this API safely can result in JIT compilers to issue invalid code causing buggy behavior and JVM
|
||||
* crashes at any time, up to and including on a field during an official match.</strong>
|
||||
*
|
||||
* <p>Teams don't need to use continuations directly with the commands framework; all mounting and
|
||||
* unmounting is handled by the command scheduler and a coroutine wrapper.
|
||||
*/
|
||||
final class Continuation {
|
||||
// The underlying jdk.internal.vm.Continuation object
|
||||
// https://github.com/openjdk/jdk/blob/jdk-21%2B35/src/java.base/share/classes/jdk/internal/vm/Continuation.java
|
||||
private final Object m_continuation;
|
||||
|
||||
static final Class<?> jdk_internal_vm_Continuation;
|
||||
private static final MethodHandle CONSTRUCTOR;
|
||||
|
||||
@SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
|
||||
private static final MethodHandle YIELD;
|
||||
|
||||
@SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
|
||||
private static final MethodHandle RUN;
|
||||
|
||||
private static final MethodHandle IS_DONE;
|
||||
|
||||
private static final MethodHandle java_lang_thread_setContinuation;
|
||||
|
||||
private static final ThreadLocal<Continuation> mountedContinuation = new ThreadLocal<>();
|
||||
|
||||
static {
|
||||
try {
|
||||
jdk_internal_vm_Continuation = Class.forName("jdk.internal.vm.Continuation");
|
||||
|
||||
var lookup =
|
||||
MethodHandles.privateLookupIn(jdk_internal_vm_Continuation, MethodHandles.lookup());
|
||||
|
||||
CONSTRUCTOR =
|
||||
lookup.findConstructor(
|
||||
jdk_internal_vm_Continuation,
|
||||
MethodType.methodType(
|
||||
void.class, ContinuationScope.jdk_internal_vm_ContinuationScope, Runnable.class));
|
||||
|
||||
YIELD =
|
||||
lookup.findStatic(
|
||||
jdk_internal_vm_Continuation,
|
||||
"yield",
|
||||
MethodType.methodType(
|
||||
boolean.class, ContinuationScope.jdk_internal_vm_ContinuationScope));
|
||||
|
||||
RUN =
|
||||
lookup.findVirtual(
|
||||
jdk_internal_vm_Continuation, "run", MethodType.methodType(void.class));
|
||||
|
||||
IS_DONE =
|
||||
lookup.findVirtual(
|
||||
jdk_internal_vm_Continuation, "isDone", MethodType.methodType(boolean.class));
|
||||
} catch (Throwable t) {
|
||||
throw new ExceptionInInitializerError(t);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
try {
|
||||
var lookup = MethodHandles.privateLookupIn(Thread.class, MethodHandles.lookup());
|
||||
|
||||
java_lang_thread_setContinuation =
|
||||
lookup.findVirtual(
|
||||
Thread.class,
|
||||
"setContinuation",
|
||||
MethodType.methodType(void.class, Continuation.jdk_internal_vm_Continuation));
|
||||
} catch (Throwable t) {
|
||||
throw new ExceptionInInitializerError(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to wrap any checked exceptions bubbled from when calling the internal continuation methods
|
||||
* via reflection. Per the Continuation API as of Java 21, none of the methods we're calling will
|
||||
* throw unchecked exceptions (IllegalState or other runtime exceptions, yes, and we bubble those
|
||||
* up directly); however, the MethodHandle API's `invoke` method has `throws Throwable` in its
|
||||
* signature and we have to handle it.
|
||||
*/
|
||||
@SuppressWarnings("PMD.DoNotExtendJavaLangError")
|
||||
static final class InternalContinuationError extends Error {
|
||||
InternalContinuationError(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
private final ContinuationScope m_scope;
|
||||
|
||||
/**
|
||||
* Constructs a continuation.
|
||||
*
|
||||
* @param scope the continuation's scope, used in yield
|
||||
* @param target the continuation's body
|
||||
*/
|
||||
@SuppressWarnings({"PMD.AvoidRethrowingException", "PMD.AvoidCatchingGenericException"})
|
||||
Continuation(ContinuationScope scope, Runnable target) {
|
||||
try {
|
||||
m_continuation = CONSTRUCTOR.invoke(scope.m_continuationScope, target);
|
||||
m_scope = scope;
|
||||
} catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspends the current continuations up to this continuation's scope.
|
||||
*
|
||||
* @return {@code true} for success; {@code false} for failure
|
||||
* @throws IllegalStateException if not currently in this continuation's scope
|
||||
*/
|
||||
@SuppressWarnings({"PMD.AvoidRethrowingException", "PMD.AvoidCatchingGenericException"})
|
||||
public boolean yield() {
|
||||
try {
|
||||
return (boolean) YIELD.invoke(m_scope.m_continuationScope);
|
||||
} catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new InternalContinuationError(
|
||||
"Continuation.yield() encountered an unexpected error", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mounts and runs the continuation body until the body calls {@link #yield()}. If the
|
||||
* continuation is suspended, it will continue from the most recent yield point.
|
||||
*/
|
||||
@SuppressWarnings({"PMD.AvoidRethrowingException", "PMD.AvoidCatchingGenericException"})
|
||||
public void run() {
|
||||
try {
|
||||
RUN.invoke(m_continuation);
|
||||
} catch (WrongMethodTypeException | ClassCastException e) {
|
||||
throw new IllegalStateException("Unable to run the underlying continuation!", e);
|
||||
} catch (RuntimeException | Error e) {
|
||||
// The bound task threw an exception; re-throw it
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new InternalContinuationError("Continuation.run() encountered an unexpected error", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether this continuation is completed.
|
||||
*
|
||||
* @return whether this continuation is completed
|
||||
*/
|
||||
@SuppressWarnings({"PMD.AvoidRethrowingException", "PMD.AvoidCatchingGenericException"})
|
||||
public boolean isDone() {
|
||||
try {
|
||||
return (boolean) IS_DONE.invoke(m_continuation);
|
||||
} catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new InternalContinuationError(
|
||||
"Continuation.isDone() encountered an unexpected error", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mounds a continuation to the current thread. Accepts null for clearing the currently mounted
|
||||
* continuation.
|
||||
*
|
||||
* @param continuation the continuation to mount
|
||||
*/
|
||||
@SuppressWarnings({"PMD.AvoidRethrowingException", "PMD.AvoidCatchingGenericException"})
|
||||
public static void mountContinuation(Continuation continuation) {
|
||||
try {
|
||||
if (continuation == null) {
|
||||
java_lang_thread_setContinuation.invoke(Thread.currentThread(), null);
|
||||
mountedContinuation.remove();
|
||||
} else {
|
||||
java_lang_thread_setContinuation.invoke(
|
||||
Thread.currentThread(), continuation.m_continuation);
|
||||
mountedContinuation.set(continuation);
|
||||
}
|
||||
} catch (RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
// `t` is anything thrown internally by Thread.setContinuation.
|
||||
// It only assigns to a field, no way to throw
|
||||
// However, if the invocation fails for some reason, we'll end up with an
|
||||
// IllegalStateException when attempting to run an unmounted continuation
|
||||
throw new InternalContinuationError(
|
||||
"Continuation.mountContinuation() encountered an unexpected error", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently mounted continuation. This is thread-local value; calling this method on two
|
||||
* different threads will give two different results.
|
||||
*
|
||||
* @return The continuation mounted on the current thread.
|
||||
*/
|
||||
public static Continuation getMountedContinuation() {
|
||||
return mountedContinuation.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return m_continuation.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("PMD.CompareObjectsWithEquals")
|
||||
boolean isMounted() {
|
||||
return this == getMountedContinuation();
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Objects;
|
||||
|
||||
/** A continuation scope. */
|
||||
final class ContinuationScope {
|
||||
// The underlying jdk.internal.vm.ContinuationScope object
|
||||
// https://github.com/openjdk/jdk/blob/jdk-21%2B35/src/java.base/share/classes/jdk/internal/vm/ContinuationScope.java
|
||||
final Object m_continuationScope;
|
||||
|
||||
static final Class<?> jdk_internal_vm_ContinuationScope;
|
||||
private static final MethodHandle CONSTRUCTOR;
|
||||
|
||||
static {
|
||||
try {
|
||||
jdk_internal_vm_ContinuationScope = Class.forName("jdk.internal.vm.ContinuationScope");
|
||||
|
||||
var lookup =
|
||||
MethodHandles.privateLookupIn(jdk_internal_vm_ContinuationScope, MethodHandles.lookup());
|
||||
|
||||
CONSTRUCTOR =
|
||||
lookup.findConstructor(
|
||||
jdk_internal_vm_ContinuationScope, MethodType.methodType(void.class, String.class));
|
||||
} catch (Throwable t) {
|
||||
throw new ExceptionInInitializerError(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new scope.
|
||||
*
|
||||
* @param name The scope's name
|
||||
*/
|
||||
ContinuationScope(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
try {
|
||||
m_continuationScope = CONSTRUCTOR.invoke(name);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return m_continuationScope.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,377 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
import static edu.wpi.first.units.Units.Seconds;
|
||||
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
|
||||
|
||||
import edu.wpi.first.units.measure.Time;
|
||||
import edu.wpi.first.wpilibj.Timer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A coroutine object is injected into command's {@link Command#run(Coroutine)} method to allow
|
||||
* commands to yield and compositions to run other commands. Commands are considered <i>bound</i> to
|
||||
* a coroutine while they're scheduled; attempting to use a coroutine outside the command bound to
|
||||
* it will result in an {@code IllegalStateException} being thrown.
|
||||
*/
|
||||
public final class Coroutine {
|
||||
private final Scheduler m_scheduler;
|
||||
private final Continuation m_backingContinuation;
|
||||
|
||||
/**
|
||||
* Creates a new coroutine. Package-private; only the scheduler should be creating these.
|
||||
*
|
||||
* @param scheduler The scheduler running the coroutine
|
||||
* @param scope The continuation scope the coroutine's backing continuation runs in
|
||||
* @param callback The callback for the continuation to execute when mounted. Often a command
|
||||
* function's body.
|
||||
*/
|
||||
Coroutine(Scheduler scheduler, ContinuationScope scope, Consumer<Coroutine> callback) {
|
||||
m_scheduler = scheduler;
|
||||
m_backingContinuation = new Continuation(scope, () -> callback.accept(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Yields control back to the scheduler to allow other commands to execute. This can be thought of
|
||||
* as "pausing" the currently executing command.
|
||||
*
|
||||
* @return true
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
*/
|
||||
public boolean yield() {
|
||||
requireMounted();
|
||||
|
||||
try {
|
||||
return m_backingContinuation.yield();
|
||||
} catch (IllegalStateException e) {
|
||||
if ("Pinned: MONITOR".equals(e.getMessage())) {
|
||||
// Raised when a continuation yields inside a synchronized block or method:
|
||||
// https://github.com/openjdk/jdk/blob/jdk-21%2B35/src/java.base/share/classes/jdk/internal/vm/Continuation.java#L396-L402
|
||||
// Note: Not a thing in Java 24+
|
||||
// Rethrow with an error message that's more helpful for our users
|
||||
throw new IllegalStateException(
|
||||
"Coroutine.yield() cannot be called inside a synchronized block or method. "
|
||||
+ "Consider using a Lock instead of synchronized, "
|
||||
+ "or rewrite your code to avoid locks and mutexes altogether.",
|
||||
e);
|
||||
} else {
|
||||
// rethrow
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parks the current command. No code in a command declared after calling {@code park()} will be
|
||||
* executed. A parked command will never complete naturally and must be interrupted or canceled.
|
||||
*
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
*/
|
||||
@SuppressWarnings("InfiniteLoopStatement")
|
||||
public void park() {
|
||||
requireMounted();
|
||||
|
||||
while (true) {
|
||||
// 'this' is required because 'yield' is a semi-keyword and needs to be qualified
|
||||
this.yield();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a child command and then immediately returns. The child command will run until its
|
||||
* natural completion, the parent command exits, or the parent command cancels it.
|
||||
*
|
||||
* <p>This is a nonblocking operation. To fork and then wait for the child command to complete,
|
||||
* use {@link #await(Command)}.
|
||||
*
|
||||
* <p>The parent command will continue executing while the child command runs, and can resync with
|
||||
* the child command using {@link #await(Command)}.
|
||||
*
|
||||
* <pre>{@code
|
||||
* Command example() {
|
||||
* return Command.noRequirements().executing(coroutine -> {
|
||||
* Command child = ...;
|
||||
* coroutine.fork(child);
|
||||
* // ... do more things
|
||||
* // then sync back up with the child command
|
||||
* coroutine.await(child);
|
||||
* }).named("Example");
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Note: forking a command that conflicts with a higher-priority command will fail. The forked
|
||||
* command will not be scheduled, and the existing command will continue to run.
|
||||
*
|
||||
* @param commands The commands to fork.
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
* @see #await(Command)
|
||||
*/
|
||||
public void fork(Command... commands) {
|
||||
requireMounted();
|
||||
|
||||
requireNonNullParam(commands, "commands", "Coroutine.fork");
|
||||
for (int i = 0; i < commands.length; i++) {
|
||||
requireNonNullParam(commands[i], "commands[" + i + "]", "Coroutine.fork");
|
||||
}
|
||||
|
||||
// Check for user error; there's no reason to fork conflicting commands simultaneously
|
||||
ConflictDetector.throwIfConflicts(List.of(commands));
|
||||
|
||||
// Shorthand; this is handy for user-defined compositions
|
||||
for (var command : commands) {
|
||||
m_scheduler.schedule(command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forks off some commands. Each command will run until its natural completion, the parent command
|
||||
* exits, or the parent command cancels it. The parent command will continue executing while the
|
||||
* forked commands run, and can resync with the forked commands using {@link
|
||||
* #awaitAll(Collection)}.
|
||||
*
|
||||
* <pre>{@code
|
||||
* Command example() {
|
||||
* return Command.noRequirements().executing(coroutine -> {
|
||||
* Collection<Command> innerCommands = ...;
|
||||
* coroutine.fork(innerCommands);
|
||||
* // ... do more things
|
||||
* // then sync back up with the inner commands
|
||||
* coroutine.awaitAll(innerCommands);
|
||||
* }).named("Example");
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Note: forking a command that conflicts with a higher-priority command will fail. The forked
|
||||
* command will not be scheduled, and the existing command will continue to run.
|
||||
*
|
||||
* @param commands The commands to fork.
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
*/
|
||||
public void fork(Collection<? extends Command> commands) {
|
||||
fork(commands.toArray(Command[]::new));
|
||||
}
|
||||
|
||||
/**
|
||||
* Awaits completion of a command. If the command is not currently scheduled or running, it will
|
||||
* be scheduled automatically. This is a blocking operation and will not return until the command
|
||||
* completes or has been interrupted by another command scheduled by the same parent.
|
||||
*
|
||||
* @param command the command to await
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
* @see #fork(Command...)
|
||||
*/
|
||||
public void await(Command command) {
|
||||
requireMounted();
|
||||
|
||||
requireNonNullParam(command, "command", "Coroutine.await");
|
||||
|
||||
m_scheduler.schedule(command);
|
||||
|
||||
while (m_scheduler.isScheduledOrRunning(command)) {
|
||||
// If the command is a one-shot, then the schedule call will completely execute the command.
|
||||
// There would be nothing to await
|
||||
this.yield();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Awaits completion of all given commands. If any command is not current scheduled or running, it
|
||||
* will be scheduled.
|
||||
*
|
||||
* @param commands the commands to await
|
||||
* @throws IllegalArgumentException if any of the commands conflict with each other
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
*/
|
||||
public void awaitAll(Collection<? extends Command> commands) {
|
||||
requireMounted();
|
||||
|
||||
requireNonNullParam(commands, "commands", "Coroutine.awaitAll");
|
||||
int i = 0;
|
||||
for (Command command : commands) {
|
||||
requireNonNullParam(command, "commands[" + i + "]", "Coroutine.awaitAll");
|
||||
i++;
|
||||
}
|
||||
|
||||
ConflictDetector.throwIfConflicts(commands);
|
||||
|
||||
for (var command : commands) {
|
||||
m_scheduler.schedule(command);
|
||||
}
|
||||
|
||||
while (commands.stream().anyMatch(m_scheduler::isScheduledOrRunning)) {
|
||||
this.yield();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Awaits completion of all given commands. If any command is not current scheduled or running, it
|
||||
* will be scheduled.
|
||||
*
|
||||
* @param commands the commands to await
|
||||
* @throws IllegalArgumentException if any of the commands conflict with each other
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
*/
|
||||
public void awaitAll(Command... commands) {
|
||||
awaitAll(Arrays.asList(commands));
|
||||
}
|
||||
|
||||
/**
|
||||
* Awaits completion of any given commands. Any command that's not already scheduled or running
|
||||
* will be scheduled. After any of the given commands completes, the rest will be canceled.
|
||||
*
|
||||
* @param commands the commands to await
|
||||
* @throws IllegalArgumentException if any of the commands conflict with each other
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
*/
|
||||
public void awaitAny(Collection<? extends Command> commands) {
|
||||
requireMounted();
|
||||
|
||||
requireNonNullParam(commands, "commands", "Coroutine.awaitAny");
|
||||
int i = 0;
|
||||
for (Command command : commands) {
|
||||
requireNonNullParam(command, "commands[" + i + "]", "Coroutine.awaitAny");
|
||||
i++;
|
||||
}
|
||||
|
||||
ConflictDetector.throwIfConflicts(commands);
|
||||
|
||||
// Schedule anything that's not already queued or running
|
||||
for (var command : commands) {
|
||||
m_scheduler.schedule(command);
|
||||
}
|
||||
|
||||
while (commands.stream().allMatch(m_scheduler::isScheduledOrRunning)) {
|
||||
this.yield();
|
||||
}
|
||||
|
||||
// At least one command exited; cancel the rest.
|
||||
commands.forEach(m_scheduler::cancel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Awaits completion of any given commands. Any command that's not already scheduled or running
|
||||
* will be scheduled. After any of the given commands completes, the rest will be canceled.
|
||||
*
|
||||
* @param commands the commands to await
|
||||
* @throws IllegalArgumentException if any of the commands conflict with each other
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
*/
|
||||
public void awaitAny(Command... commands) {
|
||||
awaitAny(Arrays.asList(commands));
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for some duration of time to elapse. Returns immediately if the given duration is zero or
|
||||
* negative. Call this within a command or command composition to introduce a simple delay.
|
||||
*
|
||||
* <p>For example, a basic autonomous routine that drives straight for 5 seconds:
|
||||
*
|
||||
* <pre>{@code
|
||||
* Command timedDrive() {
|
||||
* return drivebase.run(coroutine -> {
|
||||
* drivebase.tankDrive(1, 1);
|
||||
* coroutine.wait(Seconds.of(5));
|
||||
* drivebase.stop();
|
||||
* }).named("Timed Drive");
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Note that the resolution of the wait period is equal to the period at which {@link
|
||||
* Scheduler#run()} is called by the robot program. If using a 20 millisecond update period, the
|
||||
* wait will be rounded up to the nearest 20 millisecond interval; in this scenario, calling
|
||||
* {@code wait(Milliseconds.of(1))} and {@code wait(Milliseconds.of(19))} would have identical
|
||||
* effects.
|
||||
*
|
||||
* <p>Very small loop times near the loop period are sensitive to the order in which commands are
|
||||
* executed. If a command waits for 10 ms at the end of a scheduler cycle, and then all the
|
||||
* commands that ran before it complete or exit, and then the next cycle starts immediately, the
|
||||
* wait will be evaluated at the <i>start</i> of that next cycle, which occurred less than 10 ms
|
||||
* later. Therefore, the wait will see not enough time has passed and only exit after an
|
||||
* additional cycle elapses, adding an unexpected extra 20 ms to the wait time. This becomes less
|
||||
* of a problem with smaller loop periods, as the extra 1-loop delay becomes smaller.
|
||||
*
|
||||
* @param duration the duration of time to wait
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
*/
|
||||
public void wait(Time duration) {
|
||||
requireMounted();
|
||||
|
||||
requireNonNullParam(duration, "duration", "Coroutine.wait");
|
||||
|
||||
var timer = new Timer();
|
||||
timer.start();
|
||||
while (!timer.hasElapsed(duration.in(Seconds))) {
|
||||
this.yield();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Yields until a condition is met.
|
||||
*
|
||||
* @param condition The condition to wait for
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
*/
|
||||
public void waitUntil(BooleanSupplier condition) {
|
||||
requireMounted();
|
||||
|
||||
requireNonNullParam(condition, "condition", "Coroutine.waitUntil");
|
||||
|
||||
while (!condition.getAsBoolean()) {
|
||||
this.yield();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Advanced users only: this permits access to the backing command scheduler to run custom logic
|
||||
* not provided by the standard coroutine methods. Any commands manually scheduled through this
|
||||
* will be canceled when the parent command exits - it's not possible to "fork" a command that
|
||||
* lives longer than the command that scheduled it.
|
||||
*
|
||||
* @return the command scheduler backing this coroutine
|
||||
* @throws IllegalStateException if called anywhere other than the coroutine's running command
|
||||
*/
|
||||
public Scheduler scheduler() {
|
||||
requireMounted();
|
||||
|
||||
return m_scheduler;
|
||||
}
|
||||
|
||||
private boolean isMounted() {
|
||||
return m_backingContinuation.isMounted();
|
||||
}
|
||||
|
||||
private void requireMounted() {
|
||||
// Note: attempting to yield() outside a command will already throw an error due to the
|
||||
// continuation being unmounted, but other actions like forking and awaiting should also
|
||||
// throw errors. For consistent messaging, we use this helper in all places, not just the
|
||||
// ones that interact with the backing continuation.
|
||||
|
||||
if (isMounted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Coroutines can only be used by the command bound to them");
|
||||
}
|
||||
|
||||
// Package-private for interaction with the scheduler.
|
||||
// These functions are not intended for team use.
|
||||
|
||||
void runToYieldPoint() {
|
||||
m_backingContinuation.run();
|
||||
}
|
||||
|
||||
void mount() {
|
||||
Continuation.mountContinuation(m_backingContinuation);
|
||||
}
|
||||
|
||||
boolean isDone() {
|
||||
return m_backingContinuation.isDone();
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
import edu.wpi.first.units.measure.Time;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import org.wpilib.annotation.NoDiscard;
|
||||
|
||||
/**
|
||||
* Generic base class to represent mechanisms on a robot. Commands can require sole ownership of a
|
||||
* mechanism; when a command that requires a mechanism is running, no other commands may use it at
|
||||
* the same time.
|
||||
*
|
||||
* <p>Even though this class is named "Mechanism", it may be used to represent other physical
|
||||
* hardware on a robot that should be controlled with commands - for example, an LED strip or a
|
||||
* vision processor that can switch between different pipelines could be represented as mechanisms.
|
||||
*/
|
||||
public class Mechanism {
|
||||
private final String m_name;
|
||||
|
||||
private final Scheduler m_registeredScheduler;
|
||||
|
||||
/**
|
||||
* Creates a new mechanism registered with the default scheduler instance and named using the name
|
||||
* of the class. Intended to be used by subclasses to get sane defaults without needing to
|
||||
* manually declare a constructor.
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
protected Mechanism() {
|
||||
m_name = getClass().getSimpleName();
|
||||
m_registeredScheduler = Scheduler.getDefault();
|
||||
setDefaultCommand(idle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new mechanism, registered with the default scheduler instance.
|
||||
*
|
||||
* @param name The name of the mechanism. Cannot be null.
|
||||
*/
|
||||
public Mechanism(String name) {
|
||||
this(name, Scheduler.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new mechanism, registered with the given scheduler instance.
|
||||
*
|
||||
* @param name The name of the mechanism. Cannot be null.
|
||||
* @param scheduler The registered scheduler. Cannot be null.
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public Mechanism(String name, Scheduler scheduler) {
|
||||
m_name = name;
|
||||
m_registeredScheduler = scheduler;
|
||||
setDefaultCommand(idle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this mechanism.
|
||||
*
|
||||
* @return The name of the mechanism.
|
||||
*/
|
||||
@NoDiscard
|
||||
public String getName() {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default command to run on the mechanism when no other command is scheduled. The
|
||||
* default command's priority is effectively the minimum allowable priority for any command
|
||||
* requiring a mechanism. For this reason, it's recommended that a default command have a priority
|
||||
* less than {@link Command#DEFAULT_PRIORITY} so it doesn't prevent low-priority commands from
|
||||
* running.
|
||||
*
|
||||
* <p>The default command is initially an idle command that only owns the mechanism without doing
|
||||
* anything. This command has the lowest possible priority to allow any other command to run.
|
||||
*
|
||||
* @param defaultCommand the new default command
|
||||
*/
|
||||
public void setDefaultCommand(Command defaultCommand) {
|
||||
m_registeredScheduler.setDefaultCommand(this, defaultCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default command that was set by the latest call to {@link
|
||||
* #setDefaultCommand(Command)}.
|
||||
*
|
||||
* @return The currently configured default command
|
||||
*/
|
||||
public Command getDefaultCommand() {
|
||||
return m_registeredScheduler.getDefaultCommandFor(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts building a command that requires this mechanism.
|
||||
*
|
||||
* @param commandBody The main function body of the command.
|
||||
* @return The command builder, for further configuration.
|
||||
*/
|
||||
public NeedsNameBuilderStage run(Consumer<Coroutine> commandBody) {
|
||||
return new StagedCommandBuilder().requiring(this).executing(commandBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts building a command that requires this mechanism. The given function will be called
|
||||
* repeatedly in an infinite loop. Useful for building commands that don't need state or multiple
|
||||
* stages of logic.
|
||||
*
|
||||
* @param loopBody The body of the infinite loop.
|
||||
* @return The command builder, for further configuration.
|
||||
*/
|
||||
public NeedsNameBuilderStage runRepeatedly(Runnable loopBody) {
|
||||
return run(
|
||||
coroutine -> {
|
||||
while (true) {
|
||||
loopBody.run();
|
||||
coroutine.yield();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a command that idles this mechanism until another command claims it. The idle command
|
||||
* has {@link Command#LOWEST_PRIORITY the lowest priority} and can be interrupted by any other
|
||||
* command.
|
||||
*
|
||||
* <p>The {@link #getDefaultCommand() default command} for every mechanism is an idle command
|
||||
* unless a different default command has been configured.
|
||||
*
|
||||
* @return A new idle command.
|
||||
*/
|
||||
public Command idle() {
|
||||
return run(Coroutine::park).withPriority(Command.LOWEST_PRIORITY).named(getName() + "[IDLE]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a command that idles this mechanism for the given duration of time.
|
||||
*
|
||||
* @param duration How long the mechanism should idle for.
|
||||
* @return A new idle command.
|
||||
*/
|
||||
public Command idleFor(Time duration) {
|
||||
return idle().withTimeout(duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all running commands that require this mechanism. Commands are returned in the order in
|
||||
* which they were scheduled. The returned list is read-only. Every command in the list will have
|
||||
* been scheduled by the previous entry in the list or by intermediate commands that do not
|
||||
* require the mechanism.
|
||||
*
|
||||
* @return The currently running commands that require the mechanism.
|
||||
*/
|
||||
@NoDiscard
|
||||
public List<Command> getRunningCommands() {
|
||||
return m_registeredScheduler.getRunningCommandsFor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return m_name;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package org.wpilib.commands3;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
import org.wpilib.annotation.NoDiscard;
|
||||
|
||||
/**
|
||||
* A stage in a command builder where requirements have already been specified and execution details
|
||||
* are required. The next stage is a {@link NeedsNameBuilderStage} from {@link
|
||||
* #executing(Consumer)}. Additional requirements may still be added before moving on to the next
|
||||
* stage.
|
||||
*/
|
||||
@NoDiscard
|
||||
public interface NeedsExecutionBuilderStage {
|
||||
/**
|
||||
* Adds a required mechanism for the command.
|
||||
*
|
||||
* @param requirement A required mechanism. Cannot be null.
|
||||
* @return This builder object, for chaining
|
||||
* @throws NullPointerException If {@code requirement} is null
|
||||
*/
|
||||
NeedsExecutionBuilderStage requiring(Mechanism requirement);
|
||||
|
||||
/**
|
||||
* Adds one or more required mechanisms for the command.
|
||||
*
|
||||
* @param requirement A required mechanism. Cannot be null.
|
||||
* @param extra Any extra required mechanisms. May be empty, but cannot contain null values.
|
||||
* @return This builder object, for chaining
|
||||
* @throws NullPointerException If {@code requirement} is null or {@code extra} contains a null
|
||||
* value
|
||||
*/
|
||||
NeedsExecutionBuilderStage requiring(Mechanism requirement, Mechanism... extra);
|
||||
|
||||
/**
|
||||
* Adds required mechanisms for the command.
|
||||
*
|
||||
* @param requirements Any required mechanisms. May be empty, but cannot contain null values.
|
||||
* @return This builder object, for chaining
|
||||
* @throws NullPointerException If {@code requirements} is null or contains a null value.
|
||||
*/
|
||||
NeedsExecutionBuilderStage requiring(Collection<Mechanism> requirements);
|
||||
|
||||
/**
|
||||
* Sets the function body of the executing command.
|
||||
*
|
||||
* @param impl The command's body. Cannot be null.
|
||||
* @return A builder for the next stage of command construction.
|
||||
* @throws NullPointerException If {@code impl} is null.
|
||||
*/
|
||||
NeedsNameBuilderStage executing(Consumer<Coroutine> impl);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user