From dad88dceb857ec98fea520c516398107f96296c5 Mon Sep 17 00:00:00 2001 From: Renie Joshi Date: Mon, 20 Jul 2026 10:57:48 -0700 Subject: [PATCH 01/11] Add hardware intro page --- examples/resources/HardwareIntro.java | 41 +++++++++++++ .../spark-max-motor-controller.webp | Bin 0 -> 15632 bytes .../talonfx-motor-controller.webp | Bin 0 -> 12784 bytes src/config/sidebarConfig.ts | 19 +++--- src/content/docs/resources/hardware-intro.mdx | 55 ++++++++++++++++++ src/starlightOverrides/Header.astro | 1 + 6 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 examples/resources/HardwareIntro.java create mode 100644 public/hardware-intro/spark-max-motor-controller.webp create mode 100644 public/hardware-intro/talonfx-motor-controller.webp create mode 100644 src/content/docs/resources/hardware-intro.mdx diff --git a/examples/resources/HardwareIntro.java b/examples/resources/HardwareIntro.java new file mode 100644 index 00000000..8ecf257b --- /dev/null +++ b/examples/resources/HardwareIntro.java @@ -0,0 +1,41 @@ +/* + * Copyright 2026 FRCSoftware + * + * SPDX-License-Identifier: BSD-3-Clause + */ +public class HardwareIntro { + // [intakeSubsystem] + public class IntakeSubsystem extends SubsystemBase { + private TalonFX motor = new TalonFX(0); + + public void runIntake() { + motor.set(0.8); + } + + public void stopIntake() { + motor.set(0.0); + } + } + // [/intakeSubsystem] + + // [turret] + public class Turret extends SubsystemBase { + CANcoder encoder = new CANcoder(1, "rio"); + + public Rotation2d getEncoderPosition() { + double position = encoder.getAbsolutePosition().getValue().in(Rotations) * ENCODER_MECHANISM_RATIO; + return Rotation2d.fromRotations(position); + } + } + // [/turret] + + // [chassisSubsystem] + public class ChassisSubsystem { + private final Pigeon2 pigeon = new Pigeon2(2, "rio"); + + public Rotation2d getHeading() { + return Rotation2d.fromDegrees(pigeon.getYaw()); + } + } + // [/chassisSubsystem] +} diff --git a/public/hardware-intro/spark-max-motor-controller.webp b/public/hardware-intro/spark-max-motor-controller.webp new file mode 100644 index 0000000000000000000000000000000000000000..339a8ec4edbf31d307355e5b02b2c814aae127a4 GIT binary patch literal 15632 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 literal 0 HcmV?d00001 diff --git a/public/hardware-intro/talonfx-motor-controller.webp b/public/hardware-intro/talonfx-motor-controller.webp new file mode 100644 index 0000000000000000000000000000000000000000..8329aa86d1e09576b8bc3b7ee0686744c77a42e9 GIT binary patch literal 12784 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 literal 0 HcmV?d00001 diff --git a/src/config/sidebarConfig.ts b/src/config/sidebarConfig.ts index f47f94fb..04910fc4 100644 --- a/src/config/sidebarConfig.ts +++ b/src/config/sidebarConfig.ts @@ -263,15 +263,16 @@ export const sidebarSections: Record = { ], // Resources section (content lives at /resources but navbar says "Other Resources") - // '/resources': [ - // { - // label: 'Resources', - // items: [ - // { label: 'Overview', slug: 'resources' }, - // { label: 'Glossary', slug: 'resources/glossary' }, - // ], - // }, - // ], + '/resources': [ + { + label: 'Resources', + items: [ + { label: 'Overview', slug: 'resources' }, + { label: 'Glossary', slug: 'resources/glossary' }, + { label: 'Hardware', slug: 'resources/hardware-intro' }, + ], + }, + ], }; /** diff --git a/src/content/docs/resources/hardware-intro.mdx b/src/content/docs/resources/hardware-intro.mdx new file mode 100644 index 00000000..7cd8711c --- /dev/null +++ b/src/content/docs/resources/hardware-intro.mdx @@ -0,0 +1,55 @@ +--- +title: Hardware Intro +description: An introduction to hardware components for programmers +codeRegionSources: + default: resources/HardwareIntro.java +--- + +## Motors + +Motor controllers are used throughout the robot in many mechanisms: + +- Intakes: Spin wheels to collect game pieces +- Shooters: Spin flywheels to launch game pieces +- Indexers: Move game pieces through the robot +- Arms/Elevators: Raise and lower mechanisms (often with position control) +- Climbers: Extend or retract climbing mechanisms + +In the command-based framework, motor controllers should be encapsulated as private member variables in your subsystem class so that hardware is not exposed to the rest of the robot code. +Subsystem methods should handle motor control. + +```java #intakeSubsystem + +``` + +CAN motor controllers are available through vendors such as CTR Electronics (Talon FX) and REV Robotics (SPARK MAX). + +![TalonFX motor controller](../../../../public/hardware-intro/talonfx-motor-controller.webp#w=30) +![SPARK MAX motor controller](../../../../public/hardware-intro/spark-max-motor-controller.webp#w=20) + +## Encoders + +Encoders are a sensor for measuring rotational motion. +They are reliable and less-prone to noise and interference than analog devices (such as potentiometers) because they produce digital signals. +They can return the position and velocity of a mechanism. +Three common types of encoders in FRC are shafted encoders, on-shaft encoders, and magnetic encoders that vary in how they are mounted to mechanisms. +Many motor controllers also have integrated encoders. + +```java #turret + +``` + +## Gyroscopes + +Gyroscopes (or "gyros") are angular rate sensor used to measure the rate of rotation around an axis. +They are used to measure and control robot heading. +Gyros measure rate rather than position. +Position is inferred by integrating the rate to calculate the total change in angle. +Gyro angle measurements are always relative to some arbitrary zero angle determined by the angle of the gyro when either the robot was turned on or a zeroing method was called. +They can have accumulated errors (called “drift”) that increase in magnitude the longer the gyro is used. +The amount of drift varies with the type of gyro. +Three common types of gyros-used in FRC are single-axis gyros, three-axis gyros, and IMUs. + +```java #chassisSubsystem + +``` diff --git a/src/starlightOverrides/Header.astro b/src/starlightOverrides/Header.astro index d3861413..2d8c3c09 100644 --- a/src/starlightOverrides/Header.astro +++ b/src/starlightOverrides/Header.astro @@ -12,6 +12,7 @@ const navLinks = [ { href: '/', label: 'Home' }, { href: '/learning-course/', label: 'Learning Course' }, { href: '/educators-guide/introduction/', label: "Educator's Guide" }, + { href: '/resources/', label: 'Other Resources' }, { href: '/contribution/', label: 'Contribution' }, ]; From 0c10d17faa853d718317a143f149ec39bdc4bc34 Mon Sep 17 00:00:00 2001 From: Renie Joshi Date: Mon, 20 Jul 2026 14:54:37 -0700 Subject: [PATCH 02/11] Add other resources to home cards grid --- src/content/docs/index.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/content/docs/index.mdx b/src/content/docs/index.mdx index 0e308db8..32ab99f7 100644 --- a/src/content/docs/index.mdx +++ b/src/content/docs/index.mdx @@ -28,6 +28,12 @@ import HomeCard from '../../components/HomeCard.astro'; icon="book" description="A guide for educators implementing the FRCSoftware.org Learning Course." /> + Date: Mon, 20 Jul 2026 15:41:22 -0700 Subject: [PATCH 03/11] Add resources overview page based on FRCDesign.org --- examples/resources/HardwareIntro.java | 14 ++--- src/components/ContentCard.astro | 83 +++++++++++++++++++++++++ src/components/ContentTitleBar.astro | 48 ++++++++++++++ src/config/sidebarConfig.ts | 12 +++- src/content/docs/resources/overview.mdx | 32 ++++++++++ src/starlightOverrides/Header.astro | 2 +- 6 files changed, 180 insertions(+), 11 deletions(-) create mode 100644 src/components/ContentCard.astro create mode 100644 src/components/ContentTitleBar.astro create mode 100644 src/content/docs/resources/overview.mdx diff --git a/examples/resources/HardwareIntro.java b/examples/resources/HardwareIntro.java index 8ecf257b..a7b5b96d 100644 --- a/examples/resources/HardwareIntro.java +++ b/examples/resources/HardwareIntro.java @@ -6,15 +6,15 @@ public class HardwareIntro { // [intakeSubsystem] public class IntakeSubsystem extends SubsystemBase { - private TalonFX motor = new TalonFX(0); + private TalonFX motor = new TalonFX(0); - public void runIntake() { - motor.set(0.8); - } + public void runIntake() { + motor.set(0.8); + } - public void stopIntake() { - motor.set(0.0); - } + public void stopIntake() { + motor.set(0.0); + } } // [/intakeSubsystem] diff --git a/src/components/ContentCard.astro b/src/components/ContentCard.astro new file mode 100644 index 00000000..182308c0 --- /dev/null +++ b/src/components/ContentCard.astro @@ -0,0 +1,83 @@ +--- +import type { HTMLAttributes } from 'astro/types'; + +interface Props extends Omit, 'title'> { + title: string; + description?: string; + eyebrow?: string; + href: string; +} + +const { title, description, eyebrow, href, ...attributes } = Astro.props; +--- + + + {eyebrow &&

{eyebrow}

} +

{title}

+ {description &&

{description}

} + + +
+ + diff --git a/src/components/ContentTitleBar.astro b/src/components/ContentTitleBar.astro new file mode 100644 index 00000000..21cc1909 --- /dev/null +++ b/src/components/ContentTitleBar.astro @@ -0,0 +1,48 @@ +--- +interface Props { + label?: string; + title: string; + description?: string; +} + +const { label, title, description } = Astro.props; +--- + +
+ {label &&

{label}

} +

{title}

+ {description &&

{description}

} +
+ + diff --git a/src/config/sidebarConfig.ts b/src/config/sidebarConfig.ts index 04910fc4..697062f8 100644 --- a/src/config/sidebarConfig.ts +++ b/src/config/sidebarConfig.ts @@ -267,9 +267,15 @@ export const sidebarSections: Record = { { label: 'Resources', items: [ - { label: 'Overview', slug: 'resources' }, - { label: 'Glossary', slug: 'resources/glossary' }, - { label: 'Hardware', slug: 'resources/hardware-intro' }, + { label: 'Overview', slug: 'resources/overview' }, + { + label: 'Glossary', + slug: 'resources/glossary', + }, + { + label: 'Hardware', + slug: 'resources/hardware-intro', + }, ], }, ], diff --git a/src/content/docs/resources/overview.mdx b/src/content/docs/resources/overview.mdx new file mode 100644 index 00000000..5025670e --- /dev/null +++ b/src/content/docs/resources/overview.mdx @@ -0,0 +1,32 @@ +--- +title: Overview +description: An overview of additional programming resources +--- + +import { CardGrid } from '@astrojs/starlight/components'; +import ContentCard from '../../../components/ContentCard.astro'; +import ContentTitleBar from '../../../components/ContentTitleBar.astro'; + + + + + + + + + + diff --git a/src/starlightOverrides/Header.astro b/src/starlightOverrides/Header.astro index 2d8c3c09..9f70ae50 100644 --- a/src/starlightOverrides/Header.astro +++ b/src/starlightOverrides/Header.astro @@ -12,7 +12,7 @@ const navLinks = [ { href: '/', label: 'Home' }, { href: '/learning-course/', label: 'Learning Course' }, { href: '/educators-guide/introduction/', label: "Educator's Guide" }, - { href: '/resources/', label: 'Other Resources' }, + { href: '/resources/overview', label: 'Other Resources' }, { href: '/contribution/', label: 'Contribution' }, ]; From f2a14c1f3c2bd9b0acc4db7581ddf32572b8e070 Mon Sep 17 00:00:00 2001 From: Renie Joshi Date: Tue, 21 Jul 2026 14:03:41 -0700 Subject: [PATCH 04/11] Update HardwareIntro to commands v3 --- examples/resources/HardwareIntro.java | 51 +++++++++++++------ src/content/docs/resources/hardware-intro.mdx | 4 +- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/examples/resources/HardwareIntro.java b/examples/resources/HardwareIntro.java index a7b5b96d..70f826b4 100644 --- a/examples/resources/HardwareIntro.java +++ b/examples/resources/HardwareIntro.java @@ -3,25 +3,44 @@ * * SPDX-License-Identifier: BSD-3-Clause */ +import org.wpilib.command3.Mechanism; +import org.wpilib.hardware.imu.OnboardIMU; +import org.wpilib.hardware.imu.OnboardIMU.MountOrientation; +import org.wpilib.math.geometry.Rotation2d; + public class HardwareIntro { - // [intakeSubsystem] - public class IntakeSubsystem extends SubsystemBase { - private TalonFX motor = new TalonFX(0); + // [intake] + public class Intake implements Mechanism { + // Placeholder for TalonFX, SparkMax or SparkFlex + private final ExampleMotor motor = new ExampleMotor(0, CANBus.systemcore(0)); - public void runIntake() { - motor.set(0.8); + public Command runIntake() { + return run(coroutine -> { + while (true) { + motor.set(0.8); + coroutine.yield(); + } + }) + .named("Run Intake"); } - public void stopIntake() { - motor.set(0.0); + public Command stopIntake() { + return run(coroutine -> { + while (true) { + motor.set(0.0); + coroutine.yield(); + } + }) + .named("Stop Intake"); } } - // [/intakeSubsystem] + // [/intake] // [turret] - public class Turret extends SubsystemBase { - CANcoder encoder = new CANcoder(1, "rio"); - + public class Turret extends Mechanism { + // Placeholder for magnetic encoder + private final ExampleEncoder encoder = new ExampleEncoder(1, CANBus.systemcore(0)); + public Rotation2d getEncoderPosition() { double position = encoder.getAbsolutePosition().getValue().in(Rotations) * ENCODER_MECHANISM_RATIO; return Rotation2d.fromRotations(position); @@ -29,13 +48,13 @@ public Rotation2d getEncoderPosition() { } // [/turret] - // [chassisSubsystem] - public class ChassisSubsystem { - private final Pigeon2 pigeon = new Pigeon2(2, "rio"); + // [drivetrain] + public class Drivetrain implements Mechanism { + private final OnboardIMU imu = new OnboardIMU(MountOrientation.FLAT); public Rotation2d getHeading() { - return Rotation2d.fromDegrees(pigeon.getYaw()); + return imu.getRotation2d(); } } - // [/chassisSubsystem] + // [/drivetrain] } diff --git a/src/content/docs/resources/hardware-intro.mdx b/src/content/docs/resources/hardware-intro.mdx index 7cd8711c..4ba41b67 100644 --- a/src/content/docs/resources/hardware-intro.mdx +++ b/src/content/docs/resources/hardware-intro.mdx @@ -18,7 +18,7 @@ Motor controllers are used throughout the robot in many mechanisms: In the command-based framework, motor controllers should be encapsulated as private member variables in your subsystem class so that hardware is not exposed to the rest of the robot code. Subsystem methods should handle motor control. -```java #intakeSubsystem +```java #intake ``` @@ -50,6 +50,6 @@ They can have accumulated errors (called “drift”) that increase in magnitude The amount of drift varies with the type of gyro. Three common types of gyros-used in FRC are single-axis gyros, three-axis gyros, and IMUs. -```java #chassisSubsystem +```java #drivetrain ``` From e94bbed78f6b7a593ee10c9d16aec092726843b7 Mon Sep 17 00:00:00 2001 From: Renie Joshi Date: Tue, 21 Jul 2026 21:41:18 -0700 Subject: [PATCH 05/11] Implement requested changes --- src/content/docs/resources/hardware-intro.mdx | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/content/docs/resources/hardware-intro.mdx b/src/content/docs/resources/hardware-intro.mdx index 4ba41b67..471eba20 100644 --- a/src/content/docs/resources/hardware-intro.mdx +++ b/src/content/docs/resources/hardware-intro.mdx @@ -7,6 +7,8 @@ codeRegionSources: ## Motors +The difference between motors and motor controllers is motors are the physical actuators that move a robot's mechanisms while motor controllers are the electronic interfaces and control the speed and direction of the motor. + Motor controllers are used throughout the robot in many mechanisms: - Intakes: Spin wheels to collect game pieces @@ -15,9 +17,6 @@ Motor controllers are used throughout the robot in many mechanisms: - Arms/Elevators: Raise and lower mechanisms (often with position control) - Climbers: Extend or retract climbing mechanisms -In the command-based framework, motor controllers should be encapsulated as private member variables in your subsystem class so that hardware is not exposed to the rest of the robot code. -Subsystem methods should handle motor control. - ```java #intake ``` @@ -34,21 +33,23 @@ They are reliable and less-prone to noise and interference than analog devices ( They can return the position and velocity of a mechanism. Three common types of encoders in FRC are shafted encoders, on-shaft encoders, and magnetic encoders that vary in how they are mounted to mechanisms. Many motor controllers also have integrated encoders. +Relative encoders track changes in position and reset to zero when the robot is turned off, while absolute encoders track exact, unique positions across a full rotation and retain this data even when powered off. ```java #turret ``` -## Gyroscopes +## Inertial Measurement Units (IMUs) + +An IMU is a sensor that combines an accelerometer and a gyroscope. +IMUs are used to measure a robot's orientation, rates of rotation, and acceleration. +They can be used to control robot heading and calculate its odometry. +The most popular IMUs in FRC are navX2, Pigeon 2.0, and the onboard SystemCore IMU. -Gyroscopes (or "gyros") are angular rate sensor used to measure the rate of rotation around an axis. -They are used to measure and control robot heading. -Gyros measure rate rather than position. +One important thing to note is that gyros measure rate rather than position. Position is inferred by integrating the rate to calculate the total change in angle. -Gyro angle measurements are always relative to some arbitrary zero angle determined by the angle of the gyro when either the robot was turned on or a zeroing method was called. +Gyro angle measurements are always relative to some arbitrary zero angle determined by the angle of the gyro either when the robot was turned on or a zeroing method was called. They can have accumulated errors (called “drift”) that increase in magnitude the longer the gyro is used. -The amount of drift varies with the type of gyro. -Three common types of gyros-used in FRC are single-axis gyros, three-axis gyros, and IMUs. ```java #drivetrain From 115aec72cfa44714beecc9657c1ee8726a827954 Mon Sep 17 00:00:00 2001 From: Renie Joshi Date: Tue, 21 Jul 2026 22:02:26 -0700 Subject: [PATCH 06/11] Create robot project for resources --- examples/resources/.gitignore | 187 +++++++++++++ .../resources/.wpilib/wpilib_preferences.json | 6 + examples/resources/WPILib-License.md | 26 ++ examples/resources/build.gradle | 147 +++++++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 48966 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + examples/resources/gradlew | 248 ++++++++++++++++++ examples/resources/gradlew.bat | 93 +++++++ examples/resources/settings.gradle | 30 +++ .../java/org/wpilib/command3/Mechanism.java | 128 +++++++++ .../main/java/sources}/HardwareIntro.java | 0 examples/resources/vendordeps/CommandsV3.json | 25 ++ 12 files changed, 897 insertions(+) create mode 100644 examples/resources/.gitignore create mode 100644 examples/resources/.wpilib/wpilib_preferences.json create mode 100644 examples/resources/WPILib-License.md create mode 100644 examples/resources/build.gradle create mode 100644 examples/resources/gradle/wrapper/gradle-wrapper.jar create mode 100644 examples/resources/gradle/wrapper/gradle-wrapper.properties create mode 100644 examples/resources/gradlew create mode 100644 examples/resources/gradlew.bat create mode 100644 examples/resources/settings.gradle create mode 100644 examples/resources/src/main/java/org/wpilib/command3/Mechanism.java rename examples/resources/{ => src/main/java/sources}/HardwareIntro.java (100%) create mode 100644 examples/resources/vendordeps/CommandsV3.json diff --git a/examples/resources/.gitignore b/examples/resources/.gitignore new file mode 100644 index 00000000..34cbaac1 --- /dev/null +++ b/examples/resources/.gitignore @@ -0,0 +1,187 @@ +# This gitignore has been specially created by the WPILib team. +# If you remove items from this file, intellisense might break. + +### C++ ### +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Gradle ### +.gradle +/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +# # VS Code Specific Java Settings +# DO NOT REMOVE .classpath and .project +.classpath +.project +.settings/ +bin/ + +# IntelliJ +*.iml +*.ipr +*.iws +.idea/ +out/ + +# Fleet +.fleet + +# Simulation GUI and other tools window save file +networktables.json +simgui.json +*-window.json + +# Simulation data log directory +logs/ + +# Folder that has CTRE Phoenix Sim device config storage +ctre_sim/ + +# clangd +/.cache +compile_commands.json + +# Eclipse generated file for annotation processors +.factorypath diff --git a/examples/resources/.wpilib/wpilib_preferences.json b/examples/resources/.wpilib/wpilib_preferences.json new file mode 100644 index 00000000..19f541ed --- /dev/null +++ b/examples/resources/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2027_alpha5", + "teamNumber": 9999 +} diff --git a/examples/resources/WPILib-License.md b/examples/resources/WPILib-License.md new file mode 100644 index 00000000..c2891d4d --- /dev/null +++ b/examples/resources/WPILib-License.md @@ -0,0 +1,26 @@ +Copyright (c) 2009-2026 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +- Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/examples/resources/build.gradle b/examples/resources/build.gradle new file mode 100644 index 00000000..f729df7a --- /dev/null +++ b/examples/resources/build.gradle @@ -0,0 +1,147 @@ +plugins { + id "java" + id "org.wpilib.GradleRIO" version "2027.0.0-alpha-6" + id "com.gradleup.shadow" version "9.3.0" + id "com.diffplug.spotless" version "8.0.0" +} + +java { + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 +} + +def ROBOT_MAIN_CLASS = "" + +// Define my targets (SystemCore) and artifacts (deployable files) +// This is added by GradleRIO's backing project DeployUtils. +deploy { + targets { + systemcore(getTargetTypeClass('SystemCore')) { + // Team number is loaded either from the .wpilib/wpilib_preferences.json + // or from command line. If not found an exception will be thrown. + // You can use getTeamOrDefault(team) instead of getTeamNumber if you + // want to store a team number in this file. + team = project.wpilib.getTeamNumber() + // Use the default systemcore host name. This must be called after setting team + // as happens on the line above + useDefaultSystemcoreHostName() + debug = project.wpilib.getDebugOrDefault(false) + + artifacts { + // First part is artifact name, 2nd is artifact type + // getTargetTypeClass is a shortcut to get the class type using a string + + wpilibJava(getArtifactTypeClass('WPILibJavaArtifact')) { + } + + // Static files artifact + wpilibStaticFileDeploy(getArtifactTypeClass('FileTreeArtifact')) { + files = project.fileTree('src/main/deploy') + directory = '/home/systemcore/deploy' + deleteOldFiles = false // Change to true to delete files on systemcore that no + // longer exist in deploy directory of this project + } + } + } + } +} + +def deployArtifact = deploy.targets.systemcore.artifacts.wpilibJava + +// Set to true to use debug for all targets including JNI, which will drastically impact +// performance. +wpi.java.debugJni = false + +// Set this to true to enable desktop support. +def includeDesktopSupport = false + +// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries. +// Also defines JUnit 5. +dependencies { + annotationProcessor wpi.java.deps.wpilibAnnotations() + implementation wpi.java.deps.wpilib() + implementation wpi.java.vendor.java() + + systemcoreDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.systemcore) + systemcoreDebug wpi.java.vendor.jniDebug(wpi.platforms.systemcore) + + systemcoreRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.systemcore) + systemcoreRelease wpi.java.vendor.jniRelease(wpi.platforms.systemcore) + + nativeDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.desktop) + nativeDebug wpi.java.vendor.jniDebug(wpi.platforms.desktop) + simulationDebug wpi.sim.enableDebug() + + nativeRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.desktop) + nativeRelease wpi.java.vendor.jniRelease(wpi.platforms.desktop) + simulationRelease wpi.sim.enableRelease() + + testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +test { + useJUnitPlatform() + systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true' +} + +// Simulation configuration (e.g. environment variables). +wpi.sim.addGui().defaultEnabled = true +wpi.sim.addDriverstation() + +// Setting up my Jar File. In this case, adding all libraries into the main jar ('fat/shaded jar') +// in order to make them all available at runtime and merging service files to make JSON work. +// Also adding the manifest so WPILib knows where to look for our Robot Class. +shadowJar { + mergeServiceFiles() + from('src') { into 'backup/src' } + from('vendordeps') { into 'backup/vendordeps' } + from('build.gradle') { into 'backup' } + manifest org.wpilib.gradlerio.GradleRIOPlugin.javaManifest(ROBOT_MAIN_CLASS) + duplicatesStrategy = DuplicatesStrategy.INCLUDE +} + +// Configure jar and deploy tasks +deployArtifact.jarTask = shadowJar +wpi.java.configureExecutableTasks(shadowJar) +wpi.java.configureTestTasks(test) + +// Configure string concat to always inline compile +tasks.withType(JavaCompile) { + options.compilerArgs.add '-XDstringConcat=inline' +} + +project.compileJava.dependsOn(spotlessApply) +spotless { + java { + target fileTree(".") { + include "**/*.java" + exclude "**/build/**", "**/build-*/**" + } + toggleOffOn() + palantirJavaFormat() + leadingSpacesToTabs(4) + leadingTabsToSpaces(2) + trimTrailingWhitespace() + endWithNewline() + } + groovyGradle { + target fileTree(".") { + include "**/*.gradle" + exclude "**/build/**", "**/build-*/**" + } + greclipse() + leadingTabsToSpaces(4) + trimTrailingWhitespace() + endWithNewline() + } + format "misc", { + target fileTree(".") { + include "**/*.md", "**/.gitignore" + exclude "**/build/**", "**/build-*/**" + } + trimTrailingWhitespace() + leadingTabsToSpaces(2) + endWithNewline() + } +} diff --git a/examples/resources/gradle/wrapper/gradle-wrapper.jar b/examples/resources/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..d997cfc60f4cff0e7451d19d49a82fa986695d07 GIT binary patch literal 48966 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

`Lem|V$A>eR0uN8Y&sdjtu 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

1bvi{DS7E@q1{$_8->K{_OWv2 zCZTgG2Pr3n8|ec9kIu&uC|d?k4-cQ4#}Z`qDX5Y2mhC(jR1Ms;UG4Ho$DE|+SeJ@{ zJQQhAXj|<)*t3KiOWTuh{Wd^mS{u{&ERV)OpZwiQ%#1->r9p zSK_^*U~=?ywH~4IUxb}{0J!SmL!z2Tzq_PpetoC^_az1JFg0=gMcQADuOP%3=H1hH zH_=dG(PD;d*037Ov5G1924U#Zns?~fs+eh1%-bWqa%ssm3=nio1r3J<4G0IBETtr? zycs~0JIOn;MecYG=~OQsYHIrf?~A5>_ob%8+uOrVA+VCJw}{lygrBBdY1k<8B^wf6 zl|<%N$7)fOZX$%y>4ueco_Gb1H@B%XrKVwrn6hUOecnc^PU0rFuCB5=*2;|u-`o(@ zL*tr4bnQzXYLc4XqFbv5sK0}A)`}`8iM8ehtj#Oc5DrE;0VxbPmL@BUa_BQwa$EW~sU#-LP0?sGmqfUGhGWcciGZ*4(}u3z=@b>Ow9DQe7lcO3K}BG3j(t& zH10>sK!&4Q5-=gN@Nxj6{|*nuyqw7KZJ1?p)NUJ?U0bOigGdsOk}Iz&9PmN_5=W*Z9M zy^pA`&dX0oo6?CSuhE~(pYbLuTPp1a1Fa@e3Lu&mmgd$;D}&g-i=D-{sv?J9kIr9r zrX&Z)aFGK^kNY{LxrotP0}k*;uN12i_2a_JJhKwh zBt{D-JRxC$8U+-`u1xD>gJ^H4lbW;7spI-=H506i=ncdK;xq*L6f7jVz$XGMg5aQk zHRJY&$@g}i_SP##iC?lR?ltnWUTT-UDlq(*BTQaYNkg zNG#sNoo{WmP+Vl}U~?+T?g25b$E-7iwhu=VVgw3JdFXm~ba+LC4p>CP3~rNTiNBl7 zL{RfLLepNPEtZj}yL_#R{(^MqIlG)c0Va}>U|9Pl&B_3tV;Ps{r)WqBznD7FcTlP4 z`JQe2DvGhmeeHGGX39zGyOOxZ3tq~Dft(BQ;mDXwwJi?sBtxo$Gf1SS2w*eQ0p&RVMNVi@d zY8v4J0(n}%6*Rw(g~l@sUuxpiJ*Y}7TzBQyU+>-qWm*InUeGt@)T9g^0J#z4){Lw* zT;69if~U9DXBR9fgVPlYy7aDhJU)gDC?_GHQtwa6QXNaah7-CzA|Fx-lH7d@N9>38 zX(F&fd3w7AkZ+ha8-gKfX%@_~<#HDs?kBg5zW>V3%Xw5jwPs6uni{7r zd`EfPYrA*SU;xDtm@E>5TrJKlg5o=h;NSXk)pt4K)GbpP0xkUg>2o|oG=`UnX7^Un zb&@8d6Fj1cBWW^c(K#Csc8xEBa4KfHY>8Lp^77-lhzgWr9kR9_p+g|-9r?VSv?qA%^1O;cqgke)%AqHlR$B{!Y1Mq zj|)Ecg?{_!>kGDAwGa7%cwSUb{BcayJihkv$}ql+yu=O}jVvAFdC{Hjh$4}u+$mx% z5V$sUiGCX%D3A>bKwY8HR)Gv*lisI4q^3vJ*nDwj|mtr!0r!~+Qoe2cw^jPCXkT7tI*01|w@ z&gPC`?O1w7hQ%=&bcHi7(fqhY3${~JepA7y@^aLwHpew^Yk$;R4v{ASHjXjXtaTc_ zuz5*nXB&PrcyWx#gQ%?HyxawmS+Wu(7ssvB1UMh!1$to&o(mv_f=9~!9@VsJCGxpu z`>g5Sp=xDhpsiCy^y>=fI0DON$&pb7o7^d{@@&hj3!6PUd=vA;G;#7&8ChamsE{`^ zY8pDra8Jntp62Ivi)Y`*XbpM60s06v@Rz^-g)TW_F@B!~y7!4AJ>37mAuz!(!C+xQ zSR61?u!{N|qHWOeR%$RXRL~vpN0SGri7-klNHEJuivbi=0qSbdV4&ghf4i|7?$>z( zI{qH?i}`~a7GyB6|8pZRq982+P*r1+m-t&(%U5#ZWFQd-(CXKLHeN@y(c z;wqq1hzE@q1b$GG0VQ_)`{MeylBlVfy%UHR=;Z98>T3M&;{0i?+0T-Bck?I)AUQrz zeF**_iGu$JlCpLnFv`D9?q6R51jKPM{Rd6!0FF#KP=O|b3iQX*TqXSjO?gXaXAmLr zU#g&%@+XpjVArlGkfaPKk^PUSnMLsjlK<9nH*zxl^V2-jGC$4+HGE%?F3%4|y9>HN z|FJgz*HW$VwU8$RNtuBf(2vdZhW3x;R6%eoJM(|2zvKebxCh$s5J-*fhZ75B_yeUs zFTrToFiB^SNH?gV2>l?G&h!UD>UP%uKh1L;Er59!q&NoZRe$VEf?5Ar^&iUad&2gQ z&WE`E%lTg=_3XQT@gJOjkAi-Hbbqrl{(pA<>_GH4O8+xI^=IAhS#v+$vmgOK=>C!~_xFg-pLM>6kUfy=zL|u~KkNJ< z$L?p*?;%(Ze6w%%M(zjE|4dH&5$)_}mG3z{KUQ6s!Y@_+kInPH;kAC&{T^5HKmqz@ z@+!aA{YNIy&r;uKTz=r6e6v>d-%9<%_4R!+-iN^8H#0N(rQbiu-u&}-|2`q@k1agM zdHkW_1&%VDD_|I;NpK*OZfAjAb z`Ttl8km0{|{F`kWKWltH$^Ech;G2y`{7&N^%H;d0$cGv7Z^oJNOSiwAFaP<=em}wX z<8AA6<}bbeZc_7S=ii6PALi)3nOXL)o&Uj%-OnQ52M&L%(%ZaWiu^(R{b!Bu2WJl< h$Zw`p^gE5e2}ml*LW4$nU|{5+pXG<~Ugg7I{||-5t(pJ; literal 0 HcmV?d00001 diff --git a/examples/resources/gradle/wrapper/gradle-wrapper.properties b/examples/resources/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..42bb5ac9 --- /dev/null +++ b/examples/resources/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=permwrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=permwrapper/dists diff --git a/examples/resources/gradlew b/examples/resources/gradlew new file mode 100644 index 00000000..739907df --- /dev/null +++ b/examples/resources/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/examples/resources/gradlew.bat b/examples/resources/gradlew.bat new file mode 100644 index 00000000..c4bdd3ab --- /dev/null +++ b/examples/resources/gradlew.bat @@ -0,0 +1,93 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/examples/resources/settings.gradle b/examples/resources/settings.gradle new file mode 100644 index 00000000..e2626a81 --- /dev/null +++ b/examples/resources/settings.gradle @@ -0,0 +1,30 @@ +import org.gradle.internal.os.OperatingSystem + +pluginManagement { + repositories { + String wpilibYear = '2027_alpha5' + File wpilibHome + if (OperatingSystem.current().isWindows()) { + String publicFolder = System.getenv('PUBLIC') + if (publicFolder == null) { + publicFolder = "C:\\Users\\Public" + } + def homeRoot = new File(publicFolder, "wpilib") + wpilibHome = new File(homeRoot, wpilibYear) + } else { + def userFolder = System.getProperty("user.home") + def homeRoot = new File(userFolder, "wpilib") + wpilibHome = new File(homeRoot, wpilibYear) + } + def wpilibHomeMaven = new File(wpilibHome, 'maven') + maven { + name = 'wpilibHome' + url = wpilibHomeMaven + } + mavenLocal() + gradlePluginPortal() + } +} + +Properties props = System.getProperties(); +props.setProperty("org.gradle.internal.native.headers.unresolved.dependencies.ignore", "true"); diff --git a/examples/resources/src/main/java/org/wpilib/command3/Mechanism.java b/examples/resources/src/main/java/org/wpilib/command3/Mechanism.java new file mode 100644 index 00000000..f0cff499 --- /dev/null +++ b/examples/resources/src/main/java/org/wpilib/command3/Mechanism.java @@ -0,0 +1,128 @@ +/* + * Copyright 2026 FRCSoftware + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.wpilib.command3; + +import java.util.List; +import java.util.function.Consumer; +import org.wpilib.annotation.NoDiscard; +import org.wpilib.units.measure.Time; + +/** + * A "shim" for the `Mechanism` interface. In WPILib 2027 alpha 6, Mechanisms were still classes; + * however, alpha 7 changes them to interfaces. In an effort to not rewrite any docs, this shim will + * exist for now until alpha 7 releases. + */ +public interface Mechanism { + /** + * Returns the scheduler under which this subsystem and its default commands are registered. The + * scheduler is also used to fetch running commands for the subsystem. + * + * @return The registered scheduler. + */ + default Scheduler getRegisteredScheduler() { + return Scheduler.getDefault(); + } + + /** + * Gets the name of this mechanism. This will default to the name of this mechanism's class. + * + * @return The name of the mechanism. + */ + @NoDiscard + default String getName() { + return getClass().getSimpleName(); + } + + /** + * 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. + * + *

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 + */ + default void setDefaultCommand(Command defaultCommand) { + getRegisteredScheduler().setDefaultCommand(this, defaultCommand); + } + + /** + * Gets the default command that was set by the latest call to {@link + * #setDefaultCommand(Command)}. + * + * @return The currently configured default command + */ + default Command getDefaultCommand() { + return getRegisteredScheduler().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. + */ + default NeedsNameBuilderStage run(Consumer 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. + */ + default 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. + * + *

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. + */ + default 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. + */ + default 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 + default List getRunningCommands() { + return getRegisteredScheduler().getRunningCommandsFor(this); + } +} diff --git a/examples/resources/HardwareIntro.java b/examples/resources/src/main/java/sources/HardwareIntro.java similarity index 100% rename from examples/resources/HardwareIntro.java rename to examples/resources/src/main/java/sources/HardwareIntro.java diff --git a/examples/resources/vendordeps/CommandsV3.json b/examples/resources/vendordeps/CommandsV3.json new file mode 100644 index 00000000..f406bde7 --- /dev/null +++ b/examples/resources/vendordeps/CommandsV3.json @@ -0,0 +1,25 @@ +{ + "fileName": "CommandsV3.json", + "name": "Commands v3", + "version": "1.0.0", + "uuid": "4decdc05-a056-46cf-9561-39449bbb0130", + "wpilibYear": "2027_alpha5", + "mavenUrls": [], + "jsonUrl": "", + "conflictsWith": [ + { + "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266", + "errorMessage": "Users can not have both Commands v2 and Commands v3 vendordeps in their robot program.", + "offlineFileName": "CommandsV2.json" + } + ], + "javaDependencies": [ + { + "groupId": "org.wpilib", + "artifactId": "commands3-java", + "version": "wpilib" + } + ], + "jniDependencies": [], + "cppDependencies": [] +} From ea5a27d1a6a910fec284e4e8b8a8b7b3add6e194 Mon Sep 17 00:00:00 2001 From: Renie Joshi Date: Tue, 21 Jul 2026 22:19:41 -0700 Subject: [PATCH 07/11] Fix code region path --- src/content/docs/resources/hardware-intro.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/resources/hardware-intro.mdx b/src/content/docs/resources/hardware-intro.mdx index 471eba20..cfcb3301 100644 --- a/src/content/docs/resources/hardware-intro.mdx +++ b/src/content/docs/resources/hardware-intro.mdx @@ -2,7 +2,7 @@ title: Hardware Intro description: An introduction to hardware components for programmers codeRegionSources: - default: resources/HardwareIntro.java + default: resources/src/main/java/sources/HardwareIntro.java --- ## Motors From 79ce47642dfc468a916b247448b4d8b84dcbf6a2 Mon Sep 17 00:00:00 2001 From: Renie Joshi Date: Tue, 21 Jul 2026 23:00:39 -0700 Subject: [PATCH 08/11] Add beam brake and limit switch sections --- .../src/main/java/sources/HardwareIntro.java | 23 ++++++++++++++++++- src/content/docs/resources/hardware-intro.mdx | 18 +++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/examples/resources/src/main/java/sources/HardwareIntro.java b/examples/resources/src/main/java/sources/HardwareIntro.java index 70f826b4..75a00b82 100644 --- a/examples/resources/src/main/java/sources/HardwareIntro.java +++ b/examples/resources/src/main/java/sources/HardwareIntro.java @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ import org.wpilib.command3.Mechanism; +import org.wpilib.hardware.discrete.DigitalInput; import org.wpilib.hardware.imu.OnboardIMU; import org.wpilib.hardware.imu.OnboardIMU.MountOrientation; import org.wpilib.math.geometry.Rotation2d; @@ -37,7 +38,7 @@ public Command stopIntake() { // [/intake] // [turret] - public class Turret extends Mechanism { + public class Turret implements Mechanism { // Placeholder for magnetic encoder private final ExampleEncoder encoder = new ExampleEncoder(1, CANBus.systemcore(0)); @@ -48,6 +49,26 @@ public Rotation2d getEncoderPosition() { } // [/turret] + // [climber] + public class Climber implements Mechanism { + private final DigitalInput limitSwitch = new DigitalInput(2); + + public boolean isLimitSwitchPressed() { + return !limitSwitch.get(); + } + } + // [/climber] + + // [indexer] + public class Indexer implements Mechanism { + private final DigitalInput beamBrake = new DigitalInput(3); + + public boolean isBeanBakeTripped() { + return !beanBake.get(); + } + } + // [/indexer] + // [drivetrain] public class Drivetrain implements Mechanism { private final OnboardIMU imu = new OnboardIMU(MountOrientation.FLAT); diff --git a/src/content/docs/resources/hardware-intro.mdx b/src/content/docs/resources/hardware-intro.mdx index cfcb3301..7d799def 100644 --- a/src/content/docs/resources/hardware-intro.mdx +++ b/src/content/docs/resources/hardware-intro.mdx @@ -39,6 +39,24 @@ Relative encoders track changes in position and reset to zero when the robot is ``` +## Beam Brake + +A beam brake detects if anything is between two points. +Beam brakes can be used to detect when game pieces pass a specific point on a robot. + +```java #indexer + +``` + +## Limit Switch + +A limit switch detects if something is past a certain threshold in distance. +Limit switches are often used to restrict the range of motion of a joint or detect the presence of game pieces. + +```java #climber + +``` + ## Inertial Measurement Units (IMUs) An IMU is a sensor that combines an accelerometer and a gyroscope. From 7b4164f8a4269f43cdbe6ec6887ceb9d1441d92b Mon Sep 17 00:00:00 2001 From: Renie Joshi Date: Tue, 21 Jul 2026 23:15:09 -0700 Subject: [PATCH 09/11] Add heading and odometry to glossary --- src/data/glossary.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/data/glossary.ts b/src/data/glossary.ts index 226f3333..7351d9d5 100644 --- a/src/data/glossary.ts +++ b/src/data/glossary.ts @@ -82,6 +82,16 @@ export const glossaryTerms: GlossaryTerm[] = [ definition: 'GitHub is like Google Drive, but for code. It hosts git repositories and allows for improved collaboration on projects through pull requests and issues', }, + { + term: 'Heading', + definition: + 'The direction the robot is pointed, usually expressed as an angle in degrees', + }, + { + term: 'Odometry', + definition: + 'Using sensors on the robot to create an estimate of the pose of the robot on the field.', + }, ]; /** From 7c7a884d27a66eebb1aa6a205b1b7f12e837f655 Mon Sep 17 00:00:00 2001 From: Renie Joshi Date: Tue, 21 Jul 2026 23:20:18 -0700 Subject: [PATCH 10/11] Generate glossary --- src/content/docs/resources/glossary.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/content/docs/resources/glossary.mdx b/src/content/docs/resources/glossary.mdx index 35d98f82..0dd82cc3 100644 --- a/src/content/docs/resources/glossary.mdx +++ b/src/content/docs/resources/glossary.mdx @@ -13,6 +13,10 @@ Controller Area Network: typically yellow and green cable used to communicate wi GitHub is like Google Drive, but for code. It hosts git repositories and allows for improved collaboration on projects through pull requests and issues +**Heading** + +The direction the robot is pointed, usually expressed as an angle in degrees + **Limit Switch** Type of sensor that triggers when physically or magnetically hit. @@ -26,6 +30,10 @@ An encoder that uses a receiver and a magnet to measure position and motion Power switch for the robot +**Odometry** + +Using sensors on the robot to create an estimate of the pose of the robot on the field. + **PDH** Power Distribution Hub From 78becedc265c995d7d54ca751bf1058df3a27309 Mon Sep 17 00:00:00 2001 From: Sam Freund Date: Wed, 22 Jul 2026 11:02:14 -0700 Subject: [PATCH 11/11] update codeowners (#110) Co-authored-by: Zach Harel --- .github/CODEOWNERS | 2 +- .github/labeler.yml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 566c23b1..eee153d8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -.github/workflows @frcsoftware/ci-reviewers +.github/** package.json pnpm-workspace.yaml pnpm-lock.yaml coby.bara.sky @frcsoftware/infra diff --git a/.github/labeler.yml b/.github/labeler.yml index 12a1fb22..294214c2 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -13,3 +13,11 @@ - changed-files: - any-glob-to-any-file: - src/content/docs/** +'infra': + - changed-files: + - any-glob-to-any-file: + - .github/** + - package.json + - pnpm-lock.yaml + - pnpm-workspace.yaml + - copy.bara.sky