From 3167d357aae5a5ccdf30ef3797ee4cdb23a811e9 Mon Sep 17 00:00:00 2001 From: Alex Schokking Date: Sat, 3 Oct 2026 14:31:05 -0700 Subject: [PATCH] Rebuild the curriculum page around the wiki setup + challenge flow The pre-existing curriculum pages were LLM-written and out of sequence with the challenges we just ported. Short-term fix: make the curriculum page the setup-then-challenges flow the wiki actually teaches, and replace the overlapping pages with the wiki versions, which were just reviewed against current XbotEdu and SeriouslyCommonLib code. Ported from the wiki (wiki content wins on overlap): - onboarding.md (new) - accounts and software install - environment-setup.md - fork, clone, IntelliJ + JDK config (was VSCode-centric) - java-basics.md - the Java floor needed to start - git-introduction.md (new), clone-with-github-desktop.md (new) - robot-fundamentals/robot-architecture.md - adds Virtual Subsystems and the Operator Command Map sections; the challenges link here - robot-fundamentals/operator-command-map.md - onTrue/whileTrue instead of the removed whenPressed API Curriculum page and sidebar are now Setup -> Challenges -> Reference -> AI Tools. The three DI/Factory steps in the wiki sequence point at the deeper core-programming/patterns pages rather than duplicating them. Pages left in place but unlisted, pending the larger refactor: oop-concepts, intermediate-java, git-github, and the remaining robot-fundamentals pages. Co-Authored-By: Claude Opus 5 (1M context) --- docs/.vitepress/config.mts | 28 +- .../clone-with-github-desktop.md | 13 + .../getting-started/environment-setup.md | 299 ++--------- .../getting-started/git-introduction.md | 38 ++ .../curriculum/getting-started/java-basics.md | 467 +++++------------- docs/curriculum/getting-started/onboarding.md | 91 ++++ docs/curriculum/index.md | 105 ++-- .../operator-command-map.md | 335 +++---------- .../robot-fundamentals/robot-architecture.md | 170 ++----- 9 files changed, 496 insertions(+), 1050 deletions(-) create mode 100644 docs/curriculum/getting-started/clone-with-github-desktop.md create mode 100644 docs/curriculum/getting-started/git-introduction.md create mode 100644 docs/curriculum/getting-started/onboarding.md diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 66d11e8..d790bbd 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -45,25 +45,12 @@ export default defineConfig({ sidebar: { '/curriculum/': [ { - text: 'Getting Started', + text: 'Setup', items: [ { text: 'Overview', link: '/curriculum/' }, + { text: 'Onboarding', link: '/curriculum/getting-started/onboarding' }, { text: 'Environment Setup', link: '/curriculum/getting-started/environment-setup' }, { text: 'Java Basics', link: '/curriculum/getting-started/java-basics' }, - { text: 'Object-Oriented Programming', link: '/curriculum/getting-started/oop-concepts' }, - { text: 'Intermediate Java', link: '/curriculum/getting-started/intermediate-java' }, - { text: 'Git & GitHub Desktop', link: '/curriculum/getting-started/git-github' }, - ], - }, - { - text: 'Robot Fundamentals', - items: [ - { text: 'Robot Architecture', link: '/curriculum/robot-fundamentals/robot-architecture' }, - { text: 'Electrical Contract', link: '/curriculum/robot-fundamentals/electrical-contract' }, - { text: 'Motor Control', link: '/curriculum/robot-fundamentals/motor-control' }, - { text: 'PID Logic', link: '/curriculum/robot-fundamentals/pid-logic' }, - { text: 'Command-Based Programming', link: '/curriculum/robot-fundamentals/command-based' }, - { text: 'Operator Command Map', link: '/curriculum/robot-fundamentals/operator-command-map' }, ], }, { @@ -76,11 +63,22 @@ export default defineConfig({ { text: 'Making a Pull Request', link: '/curriculum/challenges/making-a-pull-request' }, { text: 'Rotating to a Target Orientation', link: '/curriculum/challenges/rotating-to-a-target-orientation' }, { text: 'Command Groups', link: '/curriculum/challenges/command-groups' }, + { text: 'Providers & Factories', link: '/core-programming/patterns/providers-factories' }, + { text: 'Dependency Injection', link: '/core-programming/patterns/dependency-injection' }, { text: 'Upgrading Using the SeriouslyCommonLib', link: '/curriculum/challenges/upgrading-using-seriouslycommonlib' }, { text: 'Running on a Real Robot', link: '/curriculum/challenges/running-on-a-real-robot' }, { text: 'Auto-stopping Collector', link: '/curriculum/challenges/auto-stopping-collector' }, ], }, + { + text: 'Reference', + items: [ + { text: 'Robot Architecture', link: '/curriculum/robot-fundamentals/robot-architecture' }, + { text: 'Mapping Buttons to Commands', link: '/curriculum/robot-fundamentals/operator-command-map' }, + { text: 'Git Introduction', link: '/curriculum/getting-started/git-introduction' }, + { text: 'Clone with GitHub Desktop', link: '/curriculum/getting-started/clone-with-github-desktop' }, + ], + }, { text: 'AI Tools', items: [ diff --git a/docs/curriculum/getting-started/clone-with-github-desktop.md b/docs/curriculum/getting-started/clone-with-github-desktop.md new file mode 100644 index 0000000..b272f98 --- /dev/null +++ b/docs/curriculum/getting-started/clone-with-github-desktop.md @@ -0,0 +1,13 @@ +# Clone with GitHub Desktop + +"Cloning" downloads a copy of a repository from GitHub onto your computer. These steps work for any of our repositories. + +1. Open GitHub Desktop. +1. Get to the clone dialog: + 1. If you haven't used GitHub Desktop before, you'll get an intro screen - select "Clone repository from internet". + 1. If you already have repositories cloned, choose "Clone repository..." from the "File" menu. +1. Pick the repository: + 1. If you are in our organization or are working on a fork, you can select the repository you want from the list. + 1. If you can't see the repository you want in the list, find the repository on GitHub.com, and press "Code" (the big green button). There will be an option to open the repository with GitHub Desktop. +1. Check the **Local path** before you click Clone - this is where the files land on your computer. Avoid anything inside a OneDrive folder, since OneDrive tries to sync the files the build creates and that causes trouble later. +1. Click **Clone** and wait for it to finish. diff --git a/docs/curriculum/getting-started/environment-setup.md b/docs/curriculum/getting-started/environment-setup.md index a73f149..dedaf98 100644 --- a/docs/curriculum/getting-started/environment-setup.md +++ b/docs/curriculum/getting-started/environment-setup.md @@ -1,291 +1,72 @@ # Environment Setup -Get your computer ready for FRC programming. No experience needed. +## Getting started -## What You Will Install +In this first challenge you'll get your own copy of the XbotEdu code, download it to your computer, and open it in IntelliJ so you're ready to start writing robot code. -| Software | What It Does | -|----------|-------------| -| **Java 17** | The language your robot code is written in | -| **VSCode + WPILib** | The editor where you write code | -| **Git & GitHub Desktop** | Tracks changes to your code and shares it with the team | +### Onboarding -## Install Java 17 +If you just want to do the curriculum, follow the instructions in [Edu Onboarding](/curriculum/getting-started/onboarding). -Java is the programming language you will use to control the robot. Think of it like a translator between your brain and the robot -- you write instructions in Java, and the computer turns them into commands the robot understands. +Or if you need to set up for in-season robot programming, follow the instructions in [Full Programming Onboarding](https://github.com/Team488/XbotEdu/wiki/Programming-Onboarding) instead. It covers everything in Edu Onboarding plus a few extra tools. -### Windows / macOS -1. Go to [Adoptium](https://adoptium.net/) -2. Download **Java 17 (LTS)** for your operating system -3. Run the installer and follow the prompts +**Important:** Don't continue until onboarding is complete. Missing tools cause confusing errors in the steps below. -### Linux -```bash -# Ubuntu/Debian -sudo apt install openjdk-17-jdk +### Fork the XbotEdu repository +A 'fork' is a personal copy of a code repository on GitHub. Forking a repository allows you to freely experiment with changes without affecting the original project. [More background on forking](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo). -# Verify it worked -java -version -# Should show: openjdk version "17.x.x" -``` +1. In the browser, make sure you're signed in to GitHub, then navigate to [Team488/XbotEdu](https://github.com/Team488/XbotEdu) +1. Click the **Fork** button in the upper right corner. (If a banner is covering it, close the banner first.) +1. On the "Create a new fork" page, make sure **Owner** is set to your own GitHub account, then click **Create fork**. -
-What is Java and why Java 17 specifically? +When it finishes, you'll be looking at `github.com//XbotEdu`, which is your fork. -Java is one of the most popular programming languages in the world. It is used for everything from Android apps to bank systems to robot code. FRC uses Java because it runs on the roboRIO (the robot's computer) and WPILib (the FRC library) is written for it. +### Sync the repository locally -**Why version 17?** WPILib is built specifically for Java 17, which is a Long Term Support (LTS) release. This means it will receive updates for many years. Newer versions of Java exist, but WPILib has not been updated to use them yet. Older versions are missing features WPILib needs. +"Cloning" downloads a copy of a repository from GitHub onto your computer so you can work on it. -**If you already have a different Java version:** You can install Java 17 alongside it. Your robot project will use Java 17 even if your computer has other versions installed. +1. Follow [Use GitHub Desktop to clone](/curriculum/getting-started/clone-with-github-desktop) to clone **your fork** (`/XbotEdu`, not `Team488/XbotEdu`). +1. If GitHub Desktop asks **"How are you planning to use this fork?"**, choose **For my own purposes**. Later in the curriculum you'll open pull requests against your own fork. -
+**Warning: don't clone inside of a OneDrive folder.** OneDrive tries to sync the thousands of files the build creates, which causes slow builds and strange file-locking errors. On many Windows computers the `Documents` folder is inside OneDrive, so check the **Local path** in the clone dialog. If it contains `OneDrive`, change it to something like `C:\Users\\GitHub`. -## Install VSCode + WPILib +### Open the Edu projects in IntelliJ -VSCode is the editor where you will write all your robot code. WPILib is the FRC toolkit that adds all the robot-specific features to VSCode. +1. Open the application **IntelliJ IDEA** (it may be listed as "IntelliJ IDEA Community Edition"), which you installed during the onboarding steps. +1. Click **Open** from the **Projects** tab. +1. Navigate to the XbotEdu folder you just cloned and open it. +1. If prompted, open the project as a **Gradle** project, not an Eclipse project. +1. If prompted, **Trust** the project. +1. The project will automatically start building. You can watch its progress in the status bar at the bottom of the window. -### Download WPILib -1. Go to [WPILib GitHub Releases](https://github.com/wpilibsuite/allwpilib/releases) -2. Download the installer for your OS +IntelliJ requires some additional configuration after you load a project for the first time. You need to tell it to use the Java version (JDK) that came with WPILib. -### Windows -1. Run the `.exe` installer -2. Select **"Install VSCode + WPILib"** -3. Follow the prompts +Open the main menu and choose **Project Structure...** -### macOS -1. Open the `.dmg` file -2. Drag VSCode to Applications -3. If blocked: go to **System Settings > Privacy & Security** and click **"Open Anyway"** +Main menu -### Linux -1. Extract the `.zip` installer -2. Run: `sudo ./Install-WPILib.sh` +Project settings menu item -
-What is WPILib? +On the **Project** tab, set **SDK** to "temurin-17". If it's not present, you may need to select "Add JDK from disk..." and find the JDK that you installed with WPILib, which is located at `C:\Users\Public\wpilib\\jdk` (for example, `C:\Users\Public\wpilib\2026\jdk`). -WPILib (WPI Library) is the official FRC software library made by Worcester Polytechnic Institute. It provides all the building blocks for robot control: motor control, sensors, communication, and the command-based framework. +Select SDK -**Analogy:** If building a robot program were building a house, WPILib would be the pre-made doors, windows, and plumbing. You could make everything from scratch, but the basics are already provided. +Go to the **SDKs** tab and select the same JDK (in this case, "temurin-17") and verify that the paths all start with `C:\Users\Public\wpilib\\jdk`. -**What WPILib gives you:** -- Motor controller libraries (SparkMax, TalonFX) -- Sensor libraries (gyros, encoders, cameras) -- Command-based programming framework -- Robot simulation (test without a real robot) -- Dashboard tools (SmartDashboard, Shuffleboard) +Verify correct SDK -
+Click **OK**. -
-Why VSCode and not another editor? +Open the main menu again and choose **Settings...** -WPILib only works with VSCode because the WPILib extension integrates deeply with it. You cannot use IntelliJ, Eclipse, or any other editor for FRC development. +Settings menu item -**Why VSCode is good:** -- Free on all operating systems -- WPILib extension provides one-click build, deploy, and test -- IntelliSense (autocomplete) for Java -- Built-in terminal and Git support -- Huge library of extensions +Navigate to "Build, Execution, Deployment" -> "Build Tools" -> "Gradle" in the menu on the left. In the "Gradle JVM" field, select "Project SDK", and then click **OK**. -
+Gradle Project SDK -## Install Git & GitHub Desktop +**Tip:** If IntelliJ shows build or Gradle errors after these steps, try reloading the project from the **Gradle** tool window (the elephant icon on the right side) using the **Reload All Gradle Projects** button. If errors persist, ask a mentor or teammate for help. That's what we're here for! -Git tracks changes to your code (like a save button that remembers every version). GitHub Desktop gives you a visual way to use Git without typing commands. +## Next Steps -### Install Git -- **Windows:** Download from [git-scm.com](https://git-scm.com/) and run the installer -- **macOS:** Run `git --version` in Terminal (it will prompt you to install if needed) -- **Linux:** `sudo apt install git` - -### Install GitHub Desktop -1. Go to [desktop.github.com](https://desktop.github.com/) -2. Download and install for your OS -3. Sign in with your GitHub account (create one at github.com if you do not have one) - -
-What is the difference between Git and GitHub Desktop? - -**Git** is the engine that tracks changes. It runs in the background on your computer. - -**GitHub Desktop** is a visual app that lets you use Git by clicking buttons instead of typing commands. - -**Think of it like driving a car:** -- Git = the engine and transmission (does the actual work) -- GitHub Desktop = the steering wheel and pedals (lets you control it easily) - -Both control the same thing -- GitHub Desktop just gives you buttons and menus instead of commands you have to memorize. - -
- -## Install OpenCode (AI Coding Assistant) - -OpenCode is an AI coding assistant that helps you write, understand, and debug robot code. It runs in your terminal. - -### Install OpenCode - -```bash -curl -fsSL https://opencode.ai/install | bash -``` - -Or using a package manager: - -```bash -# npm -npm install -g opencode-ai - -# macOS (Homebrew) -brew install anomalyco/tap/opencode - -# Arch Linux -sudo pacman -S opencode - -# Windows (Chocolatey) -choco install opencode -``` - -### Windows Users - -For the best experience, use [WSL (Windows Subsystem for Linux)](https://learn.microsoft.com/en-us/windows/wsl/install). OpenCode works best in a Unix-like environment. - -You will learn how to configure and use OpenCode in Module 12. - -## Verify Everything Works - -1. Open VSCode -2. Press `Ctrl+Shift+P` (Windows/Linux) or `Cmd+Shift+P` (Mac) to open the Command Palette -3. Type **"WPILib"** -- you should see WPILib commands appear - -## Clone XbotEdu (Your Practice Project) - -XbotEdu is a practice robot project with built-in tests. You can write and test robot code without owning a physical robot. - -### Using GitHub Desktop (recommended for beginners) -1. Open GitHub Desktop -2. Click **File > Clone Repository** -3. Go to the **URL** tab -4. Enter: `https://github.com/Team488/XbotEdu.git` -5. Choose where to save it on your computer -6. Click **Clone** - -### Using the command line (alternative) -```bash -git clone https://github.com/Team488/XbotEdu.git -cd XbotEdu -``` - -## Build and Test - -Once you have the project open in VSCode: - -1. Open the terminal in VSCode: **Terminal > New Terminal** -2. Build the project: - ```bash - # Windows - gradlew.bat build - - # macOS / Linux - ./gradlew build - ``` -3. Run the tests: - ```bash - # Windows - gradlew.bat test - - # macOS / Linux - ./gradlew test - ``` - -You should see **BUILD SUCCESSFUL** in the output. - -
-What does "build" actually do? - -Building is the process of turning your Java code into something the robot can run. When you run `./gradlew build`, this happens: - -1. **Download dependencies** -- Gradle downloads all the libraries your code needs -2. **Compile** -- Your `.java` files are turned into `.class` files (bytecode) -3. **Test** -- Any unit tests are run to check for bugs -4. **Package** -- Everything is bundled into a deployable format - -**The first build is slowest** because it downloads dependencies. Subsequent builds are much faster. - -
- -## Troubleshooting - -| Problem | Solution | -|---------|----------| -| `./gradlew: Permission denied` | Run `chmod +x gradlew` (macOS/Linux) | -| `Java version error` | Install Java 17 from [Adoptium](https://adoptium.net/) | -| VSCode does not show WPILib | Reinstall the WPILib extension from the marketplace | -| Build fails on first run | Wait for dependencies to download, then try again | -| GitHub Desktop cannot find repo | Make sure you typed the URL exactly right | -| "command not found" for git | Restart your terminal after installing Git | - -## Learning Java Resources - -You will learn Java in the next module, but here are excellent free resources to bookmark: - -| Resource | What It Teaches | Best For | -|----------|----------------|----------| -| [Codecademy Learn Java](https://www.codecademy.com/learn/learn-java) | Interactive coding exercises | Complete beginners | -| [W3Schools Java Tutorial](https://www.w3schools.com/java/) | Quick reference with examples | Looking things up | -| [freeCodeCamp Java Course](https://www.youtube.com/watch?v=A74TOX803D0) | 4-hour video course | Visual learners | -| [Java for Complete Beginners](https://www.udemy.com/course/java-tutorial/) | Free Udemy course | Step-by-step learners | -| [Oracle Java Tutorials](https://docs.oracle.com/javase/tutorial/) | Official Java documentation | Reference when you get stuck | - ---- - -## Quiz - -**Q1:** Why does FRC use Java 17 specifically? - -- [ ] A) It is the newest Java version -- [ ] B) WPILib is built for Java 17 -- [ ] C) Java 17 is the only free version -- [ ] D) FRC does not use Java at all - -
-Answer - -**B) WPILib is built for Java 17** - -WPILib targets Java 17 because it is a Long Term Support (LTS) release. Newer versions exist but WPILib has not been updated to use them yet. - -
- -**Q2:** What is the difference between Git and GitHub Desktop? - -- [ ] A) They are the same thing -- [ ] B) Git is the engine, GitHub Desktop is a visual app to control it -- [ ] C) GitHub Desktop is only for Windows -- [ ] D) Git only works with GitHub Desktop - -
-Answer - -**B) Git is the engine, GitHub Desktop is a visual app to control it** - -Git runs in the background and handles version control. GitHub Desktop gives you a visual interface with buttons and menus so you do not need to memorize commands. - -
- -**Q3:** What command runs the tests in XbotEdu? - -- [ ] A) `./gradlew build` -- [ ] B) `./gradlew test` -- [ ] C) `./gradlew run` -- [ ] D) `./gradlew compile` - -
-Answer - -**B) `./gradlew test`** - -The `test` command runs all unit tests in the project. `build` compiles everything (and also runs tests), but `test` specifically focuses on running the tests. - -
+Continue with the next lesson: [Java Basics](/curriculum/getting-started/java-basics) diff --git a/docs/curriculum/getting-started/git-introduction.md b/docs/curriculum/getting-started/git-introduction.md new file mode 100644 index 0000000..39fd4d0 --- /dev/null +++ b/docs/curriculum/getting-started/git-introduction.md @@ -0,0 +1,38 @@ +# Git Introduction + +## Source Control +In a nutshell: +- It's really useful to save your code somewhere that isn't just on your local computer, in case your computer dies +- If all your code is somewhere where everybody can reach it, that means everybody can work on it together +- If you keep backups of what your code was like in the past, you can go back to it if you messed something up now. + +Advanced: +- We call the code the "source code." Since we want to keep it under control (backed up, available, etc), we call solutions to this problem "Source Control." +- Source control systems such as Git or SVN let us easily back up our code and collaborate together + +## Git + +Git is the specific source control system we use. A few terms you'll see constantly: + +- **Repository** (or "repo") - a project's folder of code, plus the entire history of every change ever made to it. `XbotEdu` is a repository. +- **Clone** - make a copy of a repository on your own computer so you can work on it. See [Use GitHub Desktop to clone](/curriculum/getting-started/clone-with-github-desktop). +- **Commit** - a saved snapshot of your changes, with a short message describing what you did. Commits are the "backups of what your code was like in the past" from above. +- **Branch** - a separate line of commits. You make a branch so your half-finished work doesn't disturb everyone else. The main branch is called `main`. +- **Push** / **Pull** - send your commits up to the shared copy, or bring other people's commits down to yours. +- **Merge** - combine the commits from one branch into another. + +You don't have to memorize these. Most of what you'll do day to day is: make a branch, make some commits, push them, and open a pull request. + +Most people on the team use **GitHub Desktop**, which does all of the above with buttons instead of typed commands. Using Git from the terminal is a good thing to learn eventually, but it isn't required. + +## github.com + +Git keeps the history; **GitHub** is the website that hosts the shared copy everyone works from. Our code lives in the [Team 488 organization](https://github.com/Team488). + +GitHub also adds things Git itself doesn't have: + +- **Forks** - your own copy of someone else's repository on GitHub. The curriculum has you work in a fork of XbotEdu, so you can experiment without affecting the original. +- **Pull requests** - how you propose that your branch be merged, and how teammates review your code first. See [Making a Pull Request](/curriculum/challenges/making-a-pull-request). +- **Issues** - a place to track bugs and work to be done. + +If you want a more thorough introduction, GitHub's own [Hello World guide](https://docs.github.com/en/get-started/start-your-journey/hello-world) walks through branches, commits and pull requests in about 15 minutes. diff --git a/docs/curriculum/getting-started/java-basics.md b/docs/curriculum/getting-started/java-basics.md index a33f2d2..380c3c5 100644 --- a/docs/curriculum/getting-started/java-basics.md +++ b/docs/curriculum/getting-started/java-basics.md @@ -1,433 +1,236 @@ # Java Basics -Learn enough Java to write robot code. If you have never programmed before, start here. +## Overview -**New to programming?** You do not need any experience. This module starts from zero and teaches you exactly what you need for FRC. +FIRST Robotics Competition (FRC) robot code is written using the Java programming language. Java is popularly used by large companies in industry like Google and Amazon, but it does not have the easiest learning curve. This lesson covers the minimum you need to know to get started with writing Java code. -## What is Programming? +## IntelliJ - Your IDE -Programming is giving instructions to a computer. You write steps in a language the computer can understand (Java), and it follows those steps exactly. +We use a program called IntelliJ to write our code. IntelliJ is an IDE, an "Integrated Development Environment." IDEs provide an integrated environment full of tools to help you to write, build, and test code. In the case of IntelliJ, it is optimized for writing Java code. -**Analogy:** Think of programming like writing a recipe. You list ingredients (variables) and steps (methods). The computer is the chef that follows your recipe perfectly every time. +Other examples of IDEs that you may have heard of include: -## Learning Resources +* Visual Studio +* Eclipse +* PyCharm +* Android Studio -Everyone learns differently. Use these alongside this tutorial: +### Navigating IntelliJ -| Resource | Style | Link | -|----------|-------|------| -| **Codecademy Learn Java** | Interactive -- type code in your browser | [codecademy.com/learn/learn-java](https://www.codecademy.com/learn/learn-java) | -| **W3Schools Java** | Read and try examples | [w3schools.com/java](https://www.w3schools.com/java/) | -| **freeCodeCamp Java Course** | 4-hour video walkthrough | [youtube.com/watch?v=A74TOX803D0](https://www.youtube.com/watch?v=A74TOX803D0) | -| **Java for Complete Beginners** | Udemy free course | [udemy.com/course/java-tutorial](https://www.udemy.com/course/java-tutorial/) | -| **Programiz Java** | Tutorials with visuals | [programiz.com/java-programming](https://www.programiz.com/java-programming) | +There are a few key elements in the IntelliJ interface that you will need to familiarize yourself with: -**Tip:** If you get stuck on a concept, look it up on W3Schools or watch the freeCodeCamp video. Seeing the same idea explained differently helps it click. +#### Project and Branch selectors -## Variables (Storing Information) +The Project and Branch selectors tell you what version of the code you are working on. When working on the robot curriculum, you would usually expect the Project selector to say "XbotEdu". -Variables store data so you can use it later. Every variable has a **type** (what kind of data) and a **name** (how you refer to it). +The Branch selector may say "main", or it may show your own branch. A branch is a history of versions of your code, so you can track changes over time. Each saved version is called a "commit." -```java -// Type name = value; -int score = 42; // Whole numbers (no decimals) -double speed = 0.75; // Decimal numbers -String name = "XBot"; // Text (must be in quotes) -boolean on = true; // True or false -``` +![Project](https://github.com/user-attachments/assets/de2caa94-3138-486d-bf3c-1029765cfcfc) +![Branch](https://github.com/user-attachments/assets/3d3525eb-683f-47f5-8213-6a5205d12c70) -
-Why do I need to specify a type? +#### Project Browser -Java is a **strongly typed** language. This means every variable must have a specific type, and you cannot put the wrong kind of data in it. This prevents bugs. +The Project Browser is where you can navigate the various files that make up your project. There are two extremely important folders to know about: `src/main/java` and `src/test/java`. -**Analogy:** Think of variable types like containers: -- `int` = a box that only holds whole items (you cannot put half an apple in it) -- `double` = a measuring cup (holds any amount: 1.5, 0.75, etc.) -- `String` = a label maker (holds text only) -- `boolean` = a light switch (only on or off) +* `src/main/java` contains all the code that gets executed on your robot. +* `src/test/java` contains all the code you use to verify the correctness of the code in `src/main/java` - we call these "test cases." -```java -int x = 0.5; // ERROR! Cannot put a decimal in an int -double y = 5; // OK! Java automatically converts 5 to 5.0 -``` +The robot curriculum you are working through is primarily structured to have you implement robot code in `src/main/java` to make test cases run successfully. -**In robot code:** -- `int` for CAN IDs, port numbers, counting -- `double` for motor speeds, PID values, distances -- `String` for names, logging messages -- `boolean` for "is the button pressed?", "is the motor running?" +![Project Browser](https://github.com/user-attachments/assets/49f9bf3c-0576-46df-bd4e-26b1664ba9af) +![Code Folders](https://github.com/user-attachments/assets/5a5fad70-9ac0-4c2d-b054-b0ead291344b) -
+## Java -### Naming Rules +Java is what the industry calls an "object-oriented programming language." You don't necessarily need to understand what that means, but it carries with it some consequences that mean even the simplest code file has some components you need to be aware of. ```java -int motorSpeed; // camelCase -- start lowercase, capitalize each new word -int MotorSpeed; // Wrong convention (classes use this style, not variables) -int 2ndMotor; // ERROR! Cannot start with a number -int motor-speed; // ERROR! No hyphens allowed -int motor speed; // ERROR! No spaces allowed -``` - -**Always use descriptive names.** `speed` is better than `s`. `frontLeftMotorPower` is better than `flmp`. - -## Methods (Actions) - -A **method** is a named block of code that does something. Think of it like a command you create: "when I say `stopMotor()`, set the motor power to 0." - -```java -// Returns a value -- gives a result back -public double add(double a, double b) { - return a + b; // "return" sends the result back to the caller -} +package competition; -// Returns nothing (void) -- just does the work -public void stopMotor() { - motor.setPower(0); +public class Main { + public static void main(String... args) { + System.out.println("Hello, World!"); + } } ``` -
-Return vs Void -- what is the difference? +What does the above program do? It simply writes the text `Hello, World!` and then ends. But despite doing so little, there is a lot to know about this little block of code. -When you ask someone a question, you expect an answer back. When you give someone an order, you just want them to do it. +### Code Organization -```java -// "Return" = asking a question -double result = add(2, 3); // Returns 5.0, stored in "result" - -// "Void" = giving an order -stopMotor(); // Just does it, no result needed -``` - -**How to tell the difference:** -- `public double add(...)` -- the word `double` before the name means "this method returns a double" -- `public void stopMotor()` -- the word `void` means "this method returns nothing" - -Whenever you see `return`, the method is sending a value back. Whenever you see `void`, there is no return value. +Java code is organized into "packages." All you really need to know here is that the package declared in a code file will generally match the folder structure that the file was placed in. -
- -### Parameters (Inputs to Methods) - -Methods can take **parameters** -- information they need to do their job. +For a file with the following package declaration, it will be placed in either `src/main/java/competition` or `src/test/java/competition`. ```java -public void setMotorSpeed(double speed) { - // "speed" is a parameter -- the caller decides what value to pass - System.out.println("Setting motor to " + speed); -} - -// Calling the method: -setMotorSpeed(0.5); // Output: Setting motor to 0.5 -setMotorSpeed(-1.0); // Output: Setting motor to -1.0 +package competition; ``` -The parameter `speed` gets a different value each time you call the method. This is how you make reusable code -- one method works for any value. +IntelliJ automatically writes this line for you when you create a new file, so you usually don't need to worry about it. -## Classes & Objects +### Functions -A **class** is a blueprint. An **object** is an actual thing built from that blueprint. +All Java logic needs to live inside a function. Other code elements may live outside functions, like properties or constants, but logic always lives inside a function. -```java -// Class = the blueprint -public class Motor { - // Fields: data this class stores - private int port; // "private" means only code in this class can access it - private double power; // Current power level - - // Constructor: runs when you create a new Motor (builds the object) - public Motor(int port) { - this.port = port; // "this.port" = the field, "port" = the parameter - this.power = 0; // Start stopped - } +In the example below, we have a class (described later) with a function named `execute`. For now, you can think of a class like a container for functions, properties, or constants that can be created or destroyed. + +> [!NOTE] +> You'll hear people call these "methods" instead of "functions." In Java the two words mean the same thing in practice: a function that belongs to a class. - // Method: something this Motor can do - public void setPower(double power) { - this.power = power; +```java +public class SwerveDriveWithJoysticksCommand extends BaseCommand { + // ... omitted code ... + @Override + public void execute() { + swerveDrive.move(0, 0, 0); } } - -// Objects = actual motors built from the blueprint -Motor leftMotor = new Motor(1); // Creates a Motor on port 1 -Motor rightMotor = new Motor(2); // Creates a Motor on port 2 - -leftMotor.setPower(0.5); // Only left motor moves -rightMotor.setPower(-0.5); // Only right motor moves (reverse) ``` -
-The cookie cutter analogy for classes and objects +In a function declaration like this, `void` means that the function doesn't return anything. You could have other functions that return numbers like `double` or `int`, functions that return `String` (text), `boolean` (true/false), or "objects". The body of the function is contained within curly braces (`{}`). -A **class** is like a cookie cutter. It defines the shape but is not a cookie itself. -An **object** is an actual cookie made from that cutter. +> [!TIP] +> If you're coming from Python, in Java the indentation doesn't impact the code execution. As long as your code is within curly braces, it is treated like a block. We still indent our code for readability, even though the language does not require it. -``` -Class: Motor (blueprint) -- just a design -Object: leftMotor (port 1) -- an actual motor you can control -Object: rightMotor (port 2) -- another motor, independent -``` - -Each object is independent. Changing `leftMotor` does not affect `rightMotor`. This is important -- your robot might have 8 motors, each controlled by its own object, all created from the same class. +Sometimes functions have "annotations" - in this case `@Override`. These tell you something about the function or impact its behavior. In this case, `@Override` means that the class `BaseCommand` already has an `execute` function, and we are changing its behavior in `SwerveDriveWithJoysticksCommand`. Usually IntelliJ will manage this for you. -**In robot code:** You will write one class (like `IntakeSubsystem`) and create one object from it. But the class is the design, the object is the actual thing running on the robot. +You'll see other annotations like `@Singleton` or `@Inject` - these will be covered in more advanced lessons. Don't worry about them for now. -
+Some functions are called "constructors." They set up the context or state for a class when it is created. -### The Constructor +```java +public class SwerveDriveWithJoysticksCommand extends BaseCommand { -The **constructor** is a special method that runs when you create an object with `new`. It sets up the object's initial state. + SwerveDriveSubsystem swerveDrive; + OperatorInterface oi; -```java -public class Motor { - private int port; + @Inject + public SwerveDriveWithJoysticksCommand(SwerveDriveSubsystem driveSubsystem, OperatorInterface oi) { + this.swerveDrive = driveSubsystem; + this.oi = oi; - // Constructor: same name as the class, no return type - public Motor(int port) { - this.port = port; // Save the port number + this.addRequirements(driveSubsystem); } + // ... omitted code ... } - -// When you call this: -Motor m = new Motor(5); -// Java does: 1. Creates a blank Motor object -// 2. Calls the constructor with port=5 -// 3. Returns the finished object ``` -If you do not write a constructor, Java provides an empty one. But you usually want one to set up your object properly. - -## Inheritance (Classes Can Extend Other Classes) - -**Inheritance** lets one class get all the features of another class, then add its own. - -```java -// Parent class -- defines shared behavior -public class BaseSubsystem { - public void periodic() { - // Called every robot loop (~20ms) - // Default: do nothing - } - - public void log(String message) { - System.out.println(message); - } -} +You'll notice the `SwerveDriveWithJoysticksCommand` constructor has the same name as the class, and it doesn't have a return type. This is a feature of all constructors. In our robot code, it is very common for a constructor to have the `@Inject` annotation. -// Child class -- gets everything from BaseSubsystem, adds its own -// "extends" means DriveSubsystem IS A BaseSubsystem with extra features -public class DriveSubsystem extends BaseSubsystem { - @Override // Tells Java: "I am replacing the parent's periodic()" - public void periodic() { - // This runs instead of BaseSubsystem's periodic() - // Update motor speeds, read sensors, etc. - } +In this case, the constructor takes a couple of parameters. Each parameter is made up of a "type" followed by a "parameter name" - in `SwerveDriveSubsystem driveSubsystem`, the type is `SwerveDriveSubsystem` (the name of a class) and the parameter name is `driveSubsystem`. - // New method only DriveSubsystem has - public void drive(double speed) { - // Drive logic here - } -} -``` +> [!TIP] +> If you're coming from Python, you'll notice that Java requires you to specify types in many places, whereas Python does not require this. That is because Java is a "strongly typed" language. This makes it easier for your IDE to help you to auto-complete code, and for the process that builds your code, the "compiler" to check for errors before you ever run your code. This makes it harder to accidentally make silly mistakes like passing a number to a function where a true/false was expected. -
-Why use inheritance instead of copying code? +### Classes -Without inheritance, you would copy the same code into every class: +In object oriented programming languages, a "class" has a very specific meaning. In Java, every code file needs to contain a class, usually matching the file name. In the example below, you would expect the code to be in a file called `Main.java`. ```java -// BAD: Copy-paste in every subsystem -public class DriveSubsystem { - public void log(String msg) { System.out.println(msg); } +public class Main { + public static void main(String... args) { + System.out.println("Hello, World!"); + } } +``` -public class ShooterSubsystem { - public void log(String msg) { System.out.println(msg); } // SAME CODE -} +Notice how the body of the class is contained within curly braces (`{}`) just like a function. All blocks of code in Java use curly braces to mark the start and end of the block. -// GOOD: Write once, inherit everywhere -public class BaseSubsystem { - public void log(String msg) { System.out.println(msg); } -} +In this case, since this is a complete Java program, it needs a `main` function, but for the code you'll be writing, the `main` function is already written so you don't need to understand the meaning of it, other than that this is where a Java program starts, and only one class can have a `main` function. -public class DriveSubsystem extends BaseSubsystem { } -public class ShooterSubsystem extends BaseSubsystem { } -// Both can call log() without writing it! -``` - -This is called **Don't Repeat Yourself (DRY)**. If you find yourself copying code, you should probably use inheritance or another pattern to share it. +Classes can also contain "state" - typically called properties. (This is different from the Property system that you will learn about later! The similarity in naming is inconvenient.) -
+```java +@Singleton +public class CoralArmSubsystem extends BaseSetpointSubsystem { -## Interfaces (Contracts) + public final XCANMotorController armMotor; -An **interface** is a list of requirements. Any class that `implements` the interface must provide all the methods listed. + double periodicTickCounter; + double rotationsAtZero = 0; + boolean isCalibrated = false; -```java -// Interface: "Any electrical contract must have these methods" -public interface ElectricalContract { - double getMotorSpeed(); // Must exist - int getMotorPort(); // Must exist - boolean isMotorReady(); // Must exist -} + // ... omitted code ... -// Class that promises to fulfill the contract -public class CompetitionContract implements ElectricalContract { - @Override - public double getMotorSpeed() { - return 0.5; // Competition robot's motor speed + @Inject + public CoralArmSubsystem(XCANMotorController.XCANMotorControllerFactory xcanMotorControllerFactory, + ElectricalContract electricalContract, PropertyFactory propertyFactory, + XDutyCycleEncoder.XDutyCycleEncoderFactory xDutyCycleEncoderFactory, + XDigitalInput.XDigitalInputFactory xDigitalInputFactory) { + // ... omitted code ... } @Override - public int getMotorPort() { - return 1; // Competition robot's wiring + public boolean isCalibrated() { + return isCalibrated; } - @Override - public boolean isMotorReady() { - return true; // It is wired and ready + public void setCalibrated(boolean calibrated){ + isCalibrated = calibrated; } + // ... omitted code ... } ``` -
-Interface vs Class -- what is the difference? - -An **interface** says WHAT must exist (the method names and types). -A **class** says HOW it works (the actual code). - -**Analogy:** An interface is like a restaurant menu (listing what dishes exist). A class is the kitchen (actually cooking the food). - -``` -Interface: "There will be a way to get the motor speed" -Class: "Here is the code that gets the motor speed: return 0.5;" -``` - -**Why use interfaces:** You can swap implementations without changing the code that uses them. +### Access Modifiers -```java -// Your subsystem uses the INTERFACE, not a specific class -ElectricalContract contract; +All of the prior examples included `public` scattered throughout. Other accessibility modifiers are `private`, `protected`, and no modifier (package protected). -// It does not care WHICH contract it gets: -contract = new CompetitionContract(); // Works on competition robot -contract = new PracticeContract(); // Works on practice robot +Accessibility modifiers determine how one class can interact with another class. -// Both work because both implement ElectricalContract -double speed = contract.getMotorSpeed(); -``` +* `public` functions, classes, or properties can be accessed by any other class. +* `protected` functions or properties can be accessed by the current class or any subclasses. +* `private` functions or properties can only be accessed by the current class. +* package-private (no modifier) functions, classes, or properties are accessible to any code in the same package. -
+It is a common mistake to forget a `public` modifier on a class or function, which might prevent you from accessing it from a unit test. -## Putting It All Together +Although it's not necessarily good practice, we tend to overuse `public` for most things in robot code, so that it is easily accessible to test cases. In industry, you would typically hide internal behavior of a class using `private` or `protected` to prevent a user of your class from using it in a way that would break its internal state. -Here is how these concepts work together in a real robot class: +In the example below, we have a protected property with a `public` "getter" and "setter" function. Other classes can't touch `isCalibrated` directly, but they can read it and change it through those two functions. ```java -// A subsystem that controls the robot's intake mechanism -public class IntakeSubsystem extends BaseSubsystem { +@Singleton +public class CoralArmSubsystem extends BaseSetpointSubsystem { + protected boolean isCalibrated = false; - // Fields: data this subsystem keeps track of - private final ElectricalContract contract; - private boolean isRunning; + // ... omitted code ... - // Constructor: set up the subsystem - public IntakeSubsystem(ElectricalContract contract) { - this.contract = contract; - this.isRunning = false; - } - - // Methods: what this subsystem can do - public void startIntake() { - if (contract.isIntakeReady()) { // Check if hardware exists - isRunning = true; - System.out.println("Intake started"); - } - } - - public void stopIntake() { - isRunning = false; - System.out.println("Intake stopped"); + @Override + public boolean isCalibrated() { + return isCalibrated; } - // Returns a value (not void!) - public boolean isRunning() { - return isRunning; + public void setCalibrated(boolean calibrated){ + isCalibrated = calibrated; } + // ... omitted code ... } ``` -## Key Terms Cheat Sheet - -| Term | Meaning | Example | -|------|---------|---------| -| **Variable** | Stores a value | `int x = 5;` | -| **Method** | A named block of code | `public void run() { }` | -| **Class** | A blueprint for objects | `public class Motor { }` | -| **Object** | An instance of a class | `new Motor(1)` | -| **Constructor** | Runs when creating an object | `public Motor(int port) { }` | -| **Field** | A variable inside a class | `private int port;` | -| **Parameter** | An input to a method | `setPower(double power)` | -| **extends** | Inheritance | `class A extends B` | -| **implements** | Interface fulfillment | `class A implements B` | -| **@Override** | Replacing a parent method | `@Override public void run()` | -| **return** | Send a value back | `return 42;` | -| **void** | Returns nothing | `public void stop()` | -| **private** | Only accessible in this class | `private int x;` | -| **public** | Accessible everywhere | `public int x;` | -| **final** | Cannot be changed | `final int MAX = 100;` | -| **this** | Refers to this object | `this.port = port;` | - ---- - -## Quiz - -**Q1:** What does `extends` do in Java? - -- [ ] A) Makes the class run faster -- [ ] B) Lets one class inherit from another -- [ ] C) Deletes the parent class -- [ ] D) Creates a new object - -
-Answer +This example is simple, but you could imagine other scenarios where a "setter" changes more than one thing at the same time. If you exposed those properties as public, it is conceivable that some other class doesn't know that there is some complicated logic required to set the property correctly. -**B) Lets one class inherit from another** +### Basic Logic -`extends` creates a parent-child relationship where the child class gets all the methods and fields of the parent. This lets you reuse code instead of writing it over and over. +In Java, you can express logical operations with the following syntax: -
+| Operator | Description | +| --- | --- | +| `&&` | Logical AND | +| `\|\|` | Logical OR | +| `!` | Logical invert | +| `==` | Equality | +| `!=` | Inequality | -**Q2:** What is the difference between a class and an object? +As an example, this would be a valid Java logical expression: -- [ ] A) A class is a blueprint, an object is an actual instance -- [ ] B) They are the same thing -- [ ] C) An object is a blueprint, a class is an instance -- [ ] D) Classes cannot have methods - -
-Answer - -**A) A class is a blueprint, an object is an actual instance** - -A class defines the structure (like a cookie cutter). An object is an actual thing created from that class (like a cookie). You can create many objects from one class. - -
- -**Q3:** What is the difference between an interface and a class? - -- [ ] A) Interfaces define WHAT methods must exist, classes define HOW they work -- [ ] B) Classes are faster than interfaces -- [ ] C) Interfaces contain working code -- [ ] D) There is no difference - -
-Answer - -**A) Interfaces define WHAT must exist, classes define HOW they work** +```java +boolean isFastFood = (isHamburger || isFrenchFries) && !isHealthy; +``` -An interface is a contract that lists required methods (no code). A class provides the actual implementation. You use `implements` to connect a class to an interface. +> [!WARNING] +> `==` compares two values, while a single `=` assigns a value. Writing `if (isCalibrated = true)` instead of `if (isCalibrated == true)` is a classic bug. -
+## Next Steps +Continue with the next challenge: [Basic Robot Principles](/curriculum/challenges/basic-robot-principles) diff --git a/docs/curriculum/getting-started/onboarding.md b/docs/curriculum/getting-started/onboarding.md new file mode 100644 index 0000000..931a0b1 --- /dev/null +++ b/docs/curriculum/getting-started/onboarding.md @@ -0,0 +1,91 @@ +# Onboarding + +Welcome to Team 488 XBOT's programming discipline! This document will guide you through setting up the accounts and software you'll need to complete the XbotEdu curriculum. + +> [!NOTE] +> This document describes only the tools you'll need to complete the XbotEdu curriculum. **If you are a programming student during competition season, you'll need to set up a few additional accounts and tools.** Please see the [in-season Programming Onboarding](https://github.com/Team488/XbotEdu/wiki/Programming-Onboarding) for more instructions. + +> [!IMPORTANT] +> **Please don't skip any steps** during this onboarding process. Doing so always results in pain down the road as we try to figure out which steps you did or didn't do! + +If you run into any problems when setting up these items, don't hesitate to reach out to other people on the programming team. We're here to help! + +## Account setup + +Follow the instructions below to get accounts for the following services. + +### Team laptop + +If you are using a team laptop, **create your own user account on the laptop**. To do this, log in as the XBOT account, and use that to make your own account. Don't use the XBOT account for programming work, otherwise it's difficult for the next person to use the shared laptop. + +### GitHub + +We store all our code using version control software called Git. A central copy of each code project is hosted on a service called GitHub, to make it easier to coordinate and collaborate with the rest of the programming team. If you aren't familiar with the terms "source control" or "Git", read [Git Introduction](/curriculum/getting-started/git-introduction) and then ask a mentor if you have further questions. + +1. If you don't already have a GitHub account, [sign up](https://github.com/signup) for one. +2. Ask a programming mentor to add your GitHub account to the [Team 488 organization](https://github.com/Team488) on GitHub. +3. GitHub will send by email an invitation to join the GitHub organization. You have to click the link in this email to join the Team488 organization and get increased access to the team's code and other resources on GitHub. + +### Slack + +Slack is a chat tool that XBOT Robotics uses organization-wide as the primary team communication tool. You should already have an account in the [XBOT Slack workspace](https://xbot.slack.com/), and should check and read messages regularly. If you don't have an account, let a mentor know ASAP and they will send an invite to an email address you provide. + +Once Slack is set up on your devices, make sure you join the [\#programming](https://xbot.slack.com/archives/C03CS03M6) channel for programming discipline-specific discussions and announcements. + +## Software installation + +> [!IMPORTANT] +> If you are using a shared team laptop, it's possible that some or all of this software has already been set up. Before installing each piece of software below, check if it's already installed by searching for associated apps: +> * **GitHub Desktop:** search for the app. If it's already installed, open it and make sure it's logged in to your GitHub account +> * **WPILib:** search "AdvantageScope" and look for a version with the current year (e.g. `AdvantageScope (WPILib) 2026`) +> * **IntelliJ:** search "IntelliJ", and if it is installed, continue from step 4 in the IntelliJ section below to check that the necessary plugins are set up +> If you're unsure, please ask for help. + +> [!WARNING] +> If you're using a shared team laptop, make sure you're logged into your own account on the laptop, not the "XBOT" account. + +### GitHub Desktop + +1. Download GitHub Desktop from the [download page](https://desktop.github.com/download/). +2. Run the installer. It shouldn't ask any questions. It will open GitHub Desktop when it's done. +3. Click "Sign in to GitHub.com" and sign in with your account. + +### WPILib + +> [!TIP] +> It is easy to miss a step here, read the instructions carefully! + +> [!NOTE] +> We write our robot code in IntelliJ, so why install WPILib? The WPILib installer delivers the FRC toolchain and the Java JDK (at `C:\Users\Public\wpilib\\jdk`), which you'll point IntelliJ at in the next step of the curriculum. You need it even though you'll be working in IntelliJ. + +Go here: + +1. Follow the **WPILib Installation Guide** steps. +2. The guide sends you to the [WPILib releases page on GitHub](https://github.com/wpilibsuite/allwpilib/releases) to download the installer. Scroll down to the "Assets" section of the newest release and choose the installer for your operating system, then continue following the guide. +3. Download and run the WPILibInstaller, it will prompt you to select All Users or Current User, select either. +4. There will be checkboxes signaling whether or not you have the required files. If greyed out and checked it means it is installed, otherwise the installer will install what you need. +5. The installer offers to download VS Code. We use IntelliJ for this curriculum, so you don't need it - but installing it does no harm if you'd rather have it available. +6. After you press "Execute Install" the Install should take about 5 minutes. + +### Installing and Configuring IntelliJ + +1. Check the [FRC plugin version page](https://plugins.jetbrains.com/plugin/9405-frc/versions) to find the most recent compatible version of IntelliJ. The FRC plugin is useful, but sometimes lags behind the latest version of IntelliJ. Once you find the most recent supported IntelliJ version number, take note of it so you know what version to download in the next step. +2. Go to the [IntelliJ versions page](https://www.jetbrains.com/idea/download/other/) to download the correct version of the IntelliJ installer. Make sure you select "Community Edition" if given the option. There may be multiple download formats available; on Windows, use the `.exe` installer unless you have a reason not to. +3. Run the installer. The default settings in the installer should work fine. +4. Launch the IntelliJ app (it may be listed as "IntelliJ Community"). +5. Find the plugins tab and install the following plugins: + * [FRC](https://plugins.jetbrains.com/plugin/9405-frc) + * [CheckStyle-IDEA](https://plugins.jetbrains.com/plugin/1065-checkstyle-idea) + * [VSCode Keymap](https://plugins.jetbrains.com/plugin/12062-vscode-keymap) (optional, but recommended). +6. Restart IntelliJ to load the new plugins. +7. From the Welcome screen, on the Projects tab, find the link "Configure FRC Team Number". Enter 488 in the dialog box and save the team number. +8. From the Welcome screen, on the Customize tab, select VSCode under Keymap (optional, but recommended). + +## Done! + +Now you should have everything set up to complete the XbotEdu curriculum. Enjoy! + +Head back to [Setting up your environment](/curriculum/getting-started/environment-setup) to fork the code and open it in IntelliJ. + +> [!WARNING] +> Remember, **if you are a programming student during competition season, you'll need to set up a few additional accounts and tools.** Please see the [in-season Programming Onboarding](https://github.com/Team488/XbotEdu/wiki/Programming-Onboarding) for more instructions. diff --git a/docs/curriculum/index.md b/docs/curriculum/index.md index 3d40bb9..dcb4f0c 100644 --- a/docs/curriculum/index.md +++ b/docs/curriculum/index.md @@ -1,58 +1,63 @@ # Curriculum Overview -Welcome to the XBot programming curriculum. You will go from writing your first Java code to controlling real robot mechanisms. +Welcome to the XBot programming curriculum. You will go from writing your first Java code to making a robot drive itself. **No programming experience?** Start here. The curriculum assumes you know nothing about programming and teaches you everything step by step. -## Learning Path - -### Getting Started -| Module | What You Will Learn | Time | -|--------|-------------------|------| -| [1. Environment Setup](getting-started/environment-setup) | Install Java, VSCode, WPILib, Git, GitHub Desktop | 30 min | -| [2. Java Basics](getting-started/java-basics) | Variables, methods, classes, interfaces | 45 min | -| [3. Object-Oriented Programming](getting-started/oop-concepts) | Encapsulation, inheritance, polymorphism, abstraction | 30 min | -| [4. Intermediate Java](getting-started/intermediate-java) | Generics, lambdas, Optional, collections, streams, enums | 40 min | -| [5. Git & GitHub Desktop](getting-started/git-github) | Clone, commit, branches, pull requests | 30 min | - -### Robot Fundamentals -| Module | What You Will Learn | Time | -|--------|-------------------|------| -| [6. Robot Architecture](robot-fundamentals/robot-architecture) | How the robot program runs and is organized | 20 min | -| [7. Electrical Contract](robot-fundamentals/electrical-contract) | Wiring definitions as code | 20 min | -| [8. Motor Control](robot-fundamentals/motor-control) | Controlling motors, building a MotorSubsystem | 30 min | -| [9. PID Logic](robot-fundamentals/pid-logic) | Automatic control with Proportional-Integral-Derivative | 30 min | -| [10. Command-Based Programming](robot-fundamentals/command-based) | WPILib framework for organizing robot behavior | 30 min | -| [11. Operator Command Map](robot-fundamentals/operator-command-map) | Binding gamepad buttons to commands | 20 min | - -### Challenges - -Hands-on exercises in the [XbotEdu](https://github.com/Team488/XbotEdu) practice project. Each one has unit tests, so you can check your own work without a robot. Tackle them in order. - -| Challenge | What You Will Build | Time | -|--------|-------------------|------| -| [Basic Robot Principles](challenges/basic-robot-principles) | Watch the command scheduler run, and see commands conflict | 30 min | -| [Tank Drive](challenges/tank-drive) | Drive a robot with two joysticks | 1-2 hrs | -| [Altering Tank Drive](challenges/altering-tank-drive) | Precision mode and arcade drive, mapped to buttons | 1-2 hrs | -| [Moving to a Target Position](challenges/moving-to-a-target-position) | Drive to an exact distance and stop there | 2 hrs | -| [Making a Pull Request](challenges/making-a-pull-request) | Submit your work for review | 30 min | -| [Rotating to a Target Orientation](challenges/rotating-to-a-target-orientation) | Turn to a heading, including the tricky angle math | 2 hrs | -| [Command Groups](challenges/command-groups) | Combine commands into an autonomous square | 1-2 hrs | -| [Upgrading Using the SeriouslyCommonLib](challenges/upgrading-using-seriouslycommonlib) | Replace your own control code with the team's library | 1-2 hrs | -| [Running on a Real Robot](challenges/running-on-a-real-robot) | Deploy your code to a RoboRIO | 1 hr | -| [Auto-stopping Collector](challenges/auto-stopping-collector) | Build a subsystem and commands from scratch | 2-3 hrs | - -### AI Tools -| Module | What You Will Learn | Time | -|--------|-------------------|------| -| [12. AI Tools Setup](ai-tools/ai-tools-setup) | Configure and initialize OpenCode | 15 min | -| [13. AI Tools: Built-in Commands](ai-tools/ai-tools-commands) | Slash commands, undo, share, custom commands | 10 min | -| [14. AI Tools: Workflow Tips](ai-tools/ai-tools-workflow) | Writing prompts, Plan vs Build mode | 10 min | -| [15. Responsible AI Use](ai-tools/responsible-ai) | Ethics, code review, simulation, safety | 15 min | - -### What's Next? - -After finishing the curriculum, move on to [Core Programming](/core-programming/) to learn advanced XBot patterns like dependency injection, factories, maintainers, and swerve drive. +Work through the steps in order. Each challenge builds on the one before it. + +## Setup + +Get your accounts, tools, and a copy of the code before writing anything. + +| Step | What You Will Do | +|------|------------------| +| [Onboarding](getting-started/onboarding) | Set up accounts and install the software you need | +| [Environment Setup](getting-started/environment-setup) | Fork the practice project and open it in IntelliJ | +| [Java Basics](getting-started/java-basics) | The minimum Java you need to get started | + +## Reference + +Background you will be pointed at from the challenges, and can come back to any time. + +| Page | What It Covers | +|------|----------------| +| [Robot Architecture](robot-fundamentals/robot-architecture) | Subsystems, Commands, the Scheduler, and how they fit together | +| [Mapping Buttons to Commands](robot-fundamentals/operator-command-map) | Binding commands to gamepad buttons | +| [Git Introduction](getting-started/git-introduction) | What source control is, and the terms you will see | +| [Clone with GitHub Desktop](getting-started/clone-with-github-desktop) | Getting a copy of a repository onto your computer | + +## Challenges + +Hands-on exercises in the [XbotEdu](https://github.com/Team488/XbotEdu) practice project. Each one has unit tests, so you can check your own work without a physical robot. + +| Step | What You Will Build | +|------|---------------------| +| [Basic Robot Principles](challenges/basic-robot-principles) | Watch the command scheduler run, and see commands conflict | +| [Tank Drive](challenges/tank-drive) | Drive a robot with two joysticks | +| [Altering Tank Drive](challenges/altering-tank-drive) | Precision mode and arcade drive, mapped to buttons | +| [Moving to a Target Position](challenges/moving-to-a-target-position) | Drive to an exact distance and stop there | +| [Making a Pull Request](challenges/making-a-pull-request) | Submit your work for review | +| [Rotating to a Target Orientation](challenges/rotating-to-a-target-orientation) | Turn to a heading, including the tricky angle math | +| [Command Groups](challenges/command-groups) | Combine commands into an autonomous square | +| [Providers & Factories](/core-programming/patterns/providers-factories) | How the team's code creates objects it cannot build directly | +| [Dependency Injection](/core-programming/patterns/dependency-injection) | Why your classes are handed what they need, and how | +| [Upgrading Using the SeriouslyCommonLib](challenges/upgrading-using-seriouslycommonlib) | Replace your own control code with the team's library | +| [Running on a Real Robot](challenges/running-on-a-real-robot) | Deploy your code to a RoboRIO | +| [Auto-stopping Collector](challenges/auto-stopping-collector) | Build a subsystem and commands from scratch | + +## AI Tools + +| Module | What You Will Learn | +|--------|---------------------| +| [AI Tools Setup](ai-tools/ai-tools-setup) | Configure and initialize OpenCode | +| [Built-in Commands](ai-tools/ai-tools-commands) | Slash commands, undo, share, custom commands | +| [Workflow Tips](ai-tools/ai-tools-workflow) | Writing prompts, Plan vs Build mode | +| [Responsible AI Use](ai-tools/responsible-ai) | Ethics, code review, simulation, safety | + +## What's Next? + +After finishing the curriculum, move on to [Core Programming](/core-programming/) to learn the patterns the competition code is built on: maintainers, swerve drive, properties and tuning. ## Practice Repo diff --git a/docs/curriculum/robot-fundamentals/operator-command-map.md b/docs/curriculum/robot-fundamentals/operator-command-map.md index 42b3ec9..4c05b92 100644 --- a/docs/curriculum/robot-fundamentals/operator-command-map.md +++ b/docs/curriculum/robot-fundamentals/operator-command-map.md @@ -1,303 +1,84 @@ -# Operator Command Map +# Mapping Buttons to Commands -How buttons on the gamepad are connected to robot actions. +## Basic +If you want a robot to do something when you press a button on a gamepad or joystick, you'll need to learn about the OperatorCommandMap. -## The Problem - -You have subsystems that can do things (drive, shoot, climb) and commands that control them. But how does pressing the A button on a gamepad actually make the robot shoot? - -The **OperatorCommandMap** is the bridge. It connects every button, trigger, and D-pad direction to a specific command. - -``` -Driver presses A → OperatorCommandMap → ShooterFireCommand runs -``` - -## How XBot Organizes Button Bindings - -XBot uses three separate classes to wire everything up: - -| Class | What It Does | -|-------|-------------| -| **OperatorInterface** | Creates the gamepad objects (driver, operator, debug) | -| **OperatorCommandMap** | Binds buttons to commands | -| **SubsystemDefaultCommandMap** | Sets default commands for each subsystem | - -## OperatorInterface: The Gamepad Provider - -The `OperatorInterface` creates and exposes the gamepads. It is a `@Singleton` because there is only one set of physical controllers. - -```java -@Singleton -public class OperatorInterface { - public XXboxController driverGamepad; // Port 0 - driver - public XXboxController operatorGamepad; // Port 1 - operator - public XXboxController setupDebugGamepad; // Port 2 - debug/testing - - @Inject - public OperatorInterface( - XXboxControllerFactory controllerFactory, - PropertyFactory pf) { - - // Create gamepad on USB port 0 - driverGamepad = controllerFactory.create(0); - driverGamepad.setLeftInversion(false, true); // Invert Y-axis - driverGamepad.setRightInversion(true, true); - - operatorGamepad = controllerFactory.create(1); - setupDebugGamepad = controllerFactory.create(2); - - // Tunable deadband (how far you must push the stick before it responds) - pf.setPrefix("OperatorInterface"); - driverDeadband = pf.createPersistentProperty("Driver Deadband", 0.12); - } -} -``` - -
-What is a deadband? - -A **deadband** is a small zone near the center of a joystick where input is ignored. Joysticks do not always return exactly to 0 when released -- they might read 0.05 or 0.08. The deadband ignores tiny values so the robot does not drift when you let go of the stick. - -``` -Joystick position: -1.0 [=======DEADBAND=======] 1.0 - ↑ ↑ - -0.12 0.12 - (anything here = 0) -``` - -
- -## OperatorCommandMap: Binding Buttons to Commands - -This is where you wire every button on the gamepad to a command. XBot uses a pattern where each group of related bindings has its own setup method. +In any project based on the Robot Template, a file called OperatorCommandMap.java already exists. This is where you will be creating the mapping. In a new project, it may look like the following: ```java @Singleton public class OperatorCommandMap { - - @Inject - public OperatorCommandMap() {} // Dagger creates the singleton - - // Driver controls -- movement, aiming, resetting + + // Example for setting up a command to fire when a button is pressed: @Inject - public void setupDriveCommands( - OperatorInterface oi, - SetRobotHeadingCommand resetHeading, - PrecisionModeCommand precisionMode, - RotateToHubCommand rotateToHub) { - - // Start button -> reset robot heading to 0 - oi.driverGamepad.getifAvailable(XXboxController.XboxButton.Start) - .onTrue(resetHeading); - - // Hold Y -> precision mode (slower, finer control) - oi.driverGamepad.getifAvailable(XXboxController.XboxButton.Y) - .whileTrue(precisionMode); - - // Hold A -> rotate toward the hub - oi.driverGamepad.getifAvailable(XXboxController.XboxButton.A) - .whileTrue(rotateToHub); - - // D-Pad up -> drive to alliance trench position - oi.driverGamepad.getPovIfAvailable(0) - .onTrue(driveThroughTrenchCommand); + public void setupMyCommands( + OperatorInterface operatorInterface, + SetRobotHeadingCommand resetHeading) + { + resetHeading.setHeadingToApply(90); + operatorInterface.gamepad.getifAvailable(XboxButton.Start).onTrue(resetHeading); } - // Operator controls -- shooter, intake, climber - @Inject - public void setupOperatorCommands( - OperatorInterface oi, - ShooterFireCommand shoot, - IntakeDeployCommand deployIntake, - ClimberExtendCommand climb) { - - oi.operatorGamepad.getifAvailable(XXboxController.XboxButton.RightBumper) - .onTrue(shoot); - - oi.operatorGamepad.getifAvailable(XXboxController.XboxButton.A) - .whileTrue(deployIntake); - } } ``` -### Available Binding Methods - -WPILib provides these ways to trigger a command from a button: - -| Method | Behavior | When To Use | -|--------|----------|-------------| -| `onTrue(command)` | Runs command once when button pressed | Reset heading, toggle modes | -| `onFalse(command)` | Runs command once when button released | Cleanup when letting go | -| `whileTrue(command)` | Runs while button held, cancels on release | Driving, shooting, intake | -| `toggleOnTrue(command)` | Toggles on/off each press | Keep something running hands-free | - -
-What does getifAvailable do? - -`getifAvailable` is an XBot-specific safety feature. Each button can only be bound **once**. If you try to bind the same button twice, it throws an error at startup. - -This prevents bugs like: -```java -// BUG: Both commands try to use the same button -oi.driverGamepad.getifAvailable(XboxButton.A).onTrue(shootCommand); -oi.driverGamepad.getifAvailable(XboxButton.A).onTrue(intakeCommand); -// ERROR! Button A was already claimed by shootCommand -``` - -For D-Pad directions, use `getPovIfAvailable(angle)` where angle is 0 (up), 90 (right), 180 (down), or 270 (left). - -
+Let's break down what each important piece does. +- The function name: setupMyCommands(). Typically, we have one method for each major robot component. For example, you can see how [in the 2019 code](https://github.com/Team488/TeamXbot2019/blob/master/Competition/src/main/java/competition/operator_interface/OperatorCommandMap.java), we have methods like setupDriveCommands, setupGripperCommands, and setupElevatorCommands. +- The arguments: operatorInterface and resetHeading. You will always need the operator interface, and you need to include the commmand or commands you want to hook up to buttons. -### Chaining Bindings +In the body of the method, we do a few things: +1. Configure our commands as needed. The SetRobotHeadingCommand needs a heading to apply, so we set that first. +1. In the operator interface, we get the device the human is going to use. In this case, it is a gamepad. +1. On the gamepad, we "Get if available" the Start button. (This does some sanity checks to make sure you're not trying to use a button that somebody else already used in the code.) For a gamepad, use the `XboxButton` values rather than raw button numbers. +1. With the button, we set it to run our resetHeading command whenever the button is pressed, using `onTrue`. The useful options are: + - `onTrue` - start the command once, when the button is pressed. Good for commands that do one thing and finish. + - `whileTrue` - run the command while the button is held, and cancel it on release. Good for "do this as long as I hold the button" behavior. + - `toggleOnTrue` - start the command on the first press, cancel it on the next press. -A single button can do different things on press and release: +## Advanced +### Provider<> and using the same command over and over +You can run into a case where you need to use the same command multiple times. Perhaps you made a command called TurnToAnyAngleCommand, which needs to be given a goal angle, and you want to turn to 4 different directions. You could either do: ```java -// Hold Y to aim, release to clear the target -oi.driverGamepad.getifAvailable(XXboxController.XboxButton.Y) - .whileTrue(aimAtTargetCommand) // Starts when Y is pressed - .onFalse(clearTargetCommand); // Runs when Y is released + @Inject + public void setupTurningCommands( + OperatorInterface operatorInterface, + TurnToAnyAngleCommand turnUp, + TurnToAnyAngleCommand turnLeft, + TurnToAnyAngleCommand turnRight, + TurnToAnyAngleCommand turnDown, + ) { + turnUp.setGoal(90); + turnLeft.setGoal(180); + turnRight.setGoal(0); + turnDown.setGoal(270); + + operatorInterface.gamepad.getifAvailable(XboxButton.Y).onTrue(turnUp); + operatorInterface.gamepad.getifAvailable(XboxButton.X).onTrue(turnLeft); + operatorInterface.gamepad.getifAvailable(XboxButton.B).onTrue(turnRight); + operatorInterface.gamepad.getifAvailable(XboxButton.A).onTrue(turnDown); + } ``` -## SubsystemDefaultCommandMap: Default Behaviors - -Every subsystem needs a "resting behavior" -- what it does when no command is actively using it. This is set up in the `SubsystemDefaultCommandMap`. +Or you could use the Provider<> as follows to create the commands "on-demand": ```java -@Singleton -public class SubsystemDefaultCommandMap { - - @Inject - public SubsystemDefaultCommandMap() {} - - @Inject - public void setupDriveSubsystem( - DriveSubsystem drive, - SwerveDriveWithJoysticksCommand driveCommand) { - // When no button is pressed, drive with joysticks - drive.setDefaultCommand(driveCommand); - } - @Inject - public void setupShooterSubsystem( - ShooterSubsystem shooter, - ShooterWheelMaintainerCommand maintainer) { - // Keep shooter at idle speed when not firing - shooter.setDefaultCommand(maintainer); + public void setupTurningCommands( + OperatorInterface operatorInterface, + Provider turnProvider + ) { + operatorInterface.gamepad.getifAvailable(XboxButton.Y).onTrue(makeTurnCommand(turnProvider, 90)); + operatorInterface.gamepad.getifAvailable(XboxButton.X).onTrue(makeTurnCommand(turnProvider, 180)); + operatorInterface.gamepad.getifAvailable(XboxButton.B).onTrue(makeTurnCommand(turnProvider, 0)); + operatorInterface.gamepad.getifAvailable(XboxButton.A).onTrue(makeTurnCommand(turnProvider, 270)); } - @Inject - public void setupHopperRoller( - HopperRollerSubsystem hopper) { - // Stop when not actively running - hopper.setDefaultCommand(hopper.getStopCommand()); + private TurnToAnyAngleCommand makeTurnCommand(Provider provider, double goal) { + TurnToAnyAngleCommand command = provider.get(); + command.setGoal(goal); + return command; } -} -``` - -Default commands are typically: -- **MaintainerCommands** -- keep a mechanism at its target (PID idle) -- **Joystick drive commands** -- let the driver control when no other command claims drive -- **Stop commands** -- safely stop moving - -## How It All Connects - -Everything is wired together in `Robot.initializeSystems()`: - -```java -@Override -protected void initializeSystems() { - super.initializeSystems(); - - // 1. Set up default commands for every subsystem - getInjectorComponent().subsystemDefaultCommandMap(); - - // 2. Bind buttons to commands - getInjectorComponent().operatorCommandMap(); -} -``` - -Dagger automatically calls the `@Inject` methods in both maps when they are accessed. Simply calling `getInjectorComponent().operatorCommandMap()` triggers all the button bindings. - -### Complete Flow - -``` -Robot starts - ↓ -Robot.initializeSystems() - ↓ -subsystemDefaultCommandMap() → Every subsystem gets a default command - ↓ -operatorCommandMap() → Every button gets bound to a command - ↓ -Driver presses A button - ↓ -XXboxController detects button press - ↓ -OperatorCommandMap says: "A → ShooterFireCommand" - ↓ -ShooterFireCommand.initialize() → Sets shooter to 5000 RPM - ↓ -Command runs until isFinished() returns true ``` ---- - -## Source Code - -- [TeamXbot2026 OperatorCommandMap](https://github.com/Team488/TeamXbot2026/blob/main/src/main/java/competition/operator_interface/OperatorCommandMap.java) -- [TeamXbot2026 OperatorInterface](https://github.com/Team488/TeamXbot2026/blob/main/src/main/java/competition/operator_interface/OperatorInterface.java) -- [TeamXbot2026 SubsystemDefaultCommandMap](https://github.com/Team488/TeamXbot2026/blob/main/src/main/java/competition/subsystems/SubsystemDefaultCommandMap.java) -- [XbotEdu OperatorCommandMap](https://github.com/Team488/XbotEdu/blob/main/src/main/java/competition/operator_interface/OperatorCommandMap.java) - ---- - -## Quiz - -**Q1:** What does `getifAvailable()` do? - -- [ ] A) Checks if a gamepad is connected -- [ ] B) Claims a button and throws an error if it is already claimed -- [ ] C) Returns the battery level of the gamepad -- [ ] D) Makes the gamepad vibrate - -
-Answer - -**B) Claims a button and throws an error if it is already claimed** - -`getifAvailable` is XBot's safety mechanism that prevents two commands from binding to the same button. Each button can only be claimed once -- duplicates cause a startup error. - -
- -**Q2:** What is the difference between `onTrue(command)` and `whileTrue(command)`? - -- [ ] A) There is no difference -- [ ] B) `onTrue` runs once when pressed, `whileTrue` runs as long as the button is held -- [ ] C) `onTrue` is for the operator, `whileTrue` is for the driver -- [ ] D) `onTrue` runs in autonomous mode only - -
-Answer - -**B) `onTrue` runs once when pressed, `whileTrue` runs as long as the button is held** - -`onTrue` schedules the command once when the button transitions from released to pressed. `whileTrue` schedules the command when pressed and cancels it when released -- the command runs continuously while held. - -
- -**Q3:** Where are default commands set up? - -- [ ] A) In the OperatorCommandMap -- [ ] B) In the SubsystemDefaultCommandMap -- [ ] C) In each subsystem's constructor -- [ ] D) In the ElectricalContract - -
-Answer - -**B) In the SubsystemDefaultCommandMap** - -The `SubsystemDefaultCommandMap` is a separate class with `@Inject` methods that call `subsystem.setDefaultCommand(command)` for each subsystem. It is called during `Robot.initializeSystems()` to give every subsystem a resting behavior. - -
+Each call to `provider.get()` hands you a brand new command instance. That matters: a single Command instance can't be bound to several buttons or added to more than one CommandGroup, so when you need "the same" command in several places, a Provider is how you get separate copies of it. diff --git a/docs/curriculum/robot-fundamentals/robot-architecture.md b/docs/curriculum/robot-fundamentals/robot-architecture.md index 442b5af..04a2bab 100644 --- a/docs/curriculum/robot-fundamentals/robot-architecture.md +++ b/docs/curriculum/robot-fundamentals/robot-architecture.md @@ -1,151 +1,87 @@ # Robot Architecture -How a robot program is organized and how it runs. - -## How the Robot Runs - -When you turn on the robot, here is what happens: - -```mermaid -graph LR - A[Power On] --> B[Code starts] - B --> C[robotInit - setup once] - C --> D[autonomousInit] - D --> E[autonomousPeriodic 50x/sec] - E --> F[teleopInit] - F --> G[teleopPeriodic 50x/sec] - G --> H[disabled] - H --> D -``` +Team 488 programs its robots using a model known as the "Command" pattern. -### The Robot Lifecycle +It roughly works like this: +- A **Robot** is made out of [Subsystems](#subsystems). + - **Subsystems** have areas of responsibility. A robot might have a DriveSubsystem, an ArmSubsystem, a VisionSubsystem... + - Basically, every "thing" on the robot is contained by one **Subsystem.** +- [Commands](#commands) use **Subsystems**. One **Subsystem** will have many **Commands** that use it. + - RaiseArmCommand, LowerArmCommand, and StopArmCommand would all use the **ArmSubsystem**. + - **Commands** can use more than one **Subsystem**. You could have a RaiseArmAndDriveForwardCommand. + - **Commands** are often triggered by humans pushing joystick/gamepad buttons. +- The **Scheduler** runs Commands on the robot, and handles conflicts. It decides what happens when somebody tries to run RaiseArmCommand and LowerArmCommand at the same time. -| Method | When It Runs | What To Put Here | -|--------|-------------|-----------------| -| `robotInit()` | Once when robot turns on | Create subsystems, load settings | -| `autonomousInit()` | Once when auto starts | Set targets for auto routine | -| `autonomousPeriodic()` | 50x/sec during auto | Check sensors, run autonomous logic | -| `teleopInit()` | Once when teleop starts | Prepare for driver control | -| `teleopPeriodic()` | 50x/sec during teleop | Read joysticks, drive the robot | -**Init vs Periodic:** Init runs once (like pressing "start" on a microwave). Periodic runs 50 times per second (like the microwave constantly checking if your food is done). +WPILib also has a great page that explains the Command pattern: [What is "command-based" programming?](https://docs.wpilib.org/en/stable/docs/software/commandbased/what-is-command-based.html) -## Project Structure +## More Details -How the XBot codebase is organized: +### Subsystems +Subsystems are responsible for all of the direct communication with physical devices on the robot (things like motors, sensors etc..). They provide a single place for Commands that need to use these things to do so in a clean, abstract manner. -``` -TeamXbot2026/ -├── src/ -│ └── main/java/competition/ -│ ├── electrical_contract/ # Wiring definitions (which motor on which port) -│ ├── subsystems/ # Robot mechanisms (drive, shooter, intake) -│ │ ├── drive/ -│ │ ├── shooter/ -│ │ └── intake/ -│ ├── operator_interface/ # Gamepad button bindings -│ └── Robot.java # Main robot class (lifecycle) -``` +#### Motivation +For example, imagine a robot that has 2 motors on it (1 per side). All code that needs to move the robot needs to communicate with these 2 motors (this could be a lot of places in the code). Over time the robot might change and now there are 4 motors instead of 2, all of the places that were talking to the motors need to be updated to account for this change. In order to avoid having to do this bulk updating of code, we use a Subsystem to wrap the motors (however many there are) and just expose out methods that aren't likely to change for others to use. -
-What is a Subsystem? +### Commands -A **subsystem** represents one physical part of the robot. Think of it like an organ in a body -- each organ has a specific job: +This diagram helps show the lifecycle that a Command goes through: [Commands](https://github.com/Team488/SeriouslyCommonLib/wiki/Commands) -- **DriveSubsystem** = legs (moves the robot) -- **ShooterSubsystem** = arm (shoots game pieces) -- **IntakeSubsystem** = hand (picks up game pieces) +#### Starting commands +On the real robot, commands are often started by a human pushing a joystick button. For example the operator might push a button to run the intake to suck balls into the robot. They can also be manually started by calling `.schedule()` on the command (which you will see in the tests sometimes). -Each subsystem controls its own motors and sensors, and provides methods for other code to use. +#### Requires +Requires is the way to ensure that only 1 command is telling motors/mechanisms what to do at any given time. For example if you had a command called DriveForward and another one called StopDrive you wouldn't want them both running at the same time or they would fight over the motors and bad things would happen. -
+A Command can "require" one or more subsystems. What this means in practice is that when this command starts running if there were any commands already running that also required any of these subsystems, those existing commands will be cancelled. -## The Entry Point +#### Default commands +A Subsystem can optionally have 1 default command specified. This command will be run whenever no other commands that require the subsystem are running. This can be really useful for providing a safe default behavior (for instance for an arm that can move perhaps by default you want to stop its motors so it doesn't hurt itself). Another common use is for a subsystem that will really only have 1 command that ever runs on it and it should be running all the time. -```java -// Main.java -- the first code that runs when the robot turns on -public final class Main { - public static void main(String... args) { - RobotBase.startRobot(Robot::new); - } -} -``` +Default Commands for Subsystems are specified in the `SubsystemDefaultCommandMap` class. A default Command must require the Subsystem it is the default for. -You should never need to modify this file. It is the same for every FRC robot. +#### Operator Command Map -## The Robot Class +Default commands handle what a Subsystem does when nothing else is happening. The other way Commands get started is a human pressing a button, and those bindings all live in one place: the `OperatorCommandMap` class. + +A binding looks like this - ask for the command you want in the method's parameters, then attach it to a button: ```java -public class Robot extends BaseRobot { - @Override - protected void initializeSystems() { - super.initializeSystems(); - // Connect buttons to commands, set default behaviors - getInjectorComponent().subsystemDefaultCommandMap(); - getInjectorComponent().operatorCommandMap(); - } -} +operatorInterface.gamepad.getifAvailable(XboxButton.A).whileTrue(togglePrecisionDriveCommand); ``` -This is where everything gets connected together. You will learn more about this as you progress through the curriculum. - -## Core Programming vs Vision - -| Team | What They Work On | -|------|------------------| -| **Core Programming** | Drive, shooter, intake, autonomous, robot infrastructure | -| **Vision** (future) | AprilTag detection, camera processing, path planning | - -You will start on **Core Programming**. Vision is a separate team you can join later. - ---- +Keeping every binding in one class means you can answer "what does the A button do?" by reading a single file, instead of hunting through every Command. -## Quiz +See [Mapping Buttons to Commands](/curriculum/robot-fundamentals/operator-command-map) for more detail, including what to do when you need the same Command bound to several buttons. -**Q1:** How many times per second does `teleopPeriodic()` run? +### Virtual Subsystems -- [ ] A) Once -- [ ] B) 5 times per second -- [ ] C) 50 times per second -- [ ] D) 500 times per second +A Subsystem usually represents real hardware, but it is doing two jobs at once: it owns the devices, **and** it acts as a lock. Whenever a Command requires a Subsystem, the Scheduler guarantees that no other Command requiring that same Subsystem runs at the same time. -
-Answer +Sometimes we want that locking behavior without attaching it to hardware. For that we create a Subsystem that owns nothing at all - a "virtual subsystem" - and have Commands require it instead. -**C) 50 times per second** +The clearest example is the setpoint + maintainer pattern in SeriouslyCommonLib's `BaseSetpointSubsystem`. It creates an empty Subsystem to use purely as a lock: -The robot control loop runs at 50Hz, meaning `periodic()` methods are called every 20 milliseconds. This is fast enough to feel responsive to the driver. - -
- -**Q2:** What does `robotInit()` do? - -- [ ] A) Runs 50 times per second -- [ ] B) Runs once when the robot turns on -- [ ] C) Runs when a button is pressed -- [ ] D) Runs when the match ends - -
-Answer - -**B) Runs once when the robot turns on** - -`robotInit()` runs exactly once at startup to set up subsystems, load settings, and prepare the robot. +```java + private final Subsystem setpointLock; -
+ public BaseSetpointSubsystem() { + setpointLock = new Subsystem() {}; + } +``` -**Q3:** What does a subsystem represent? +Two different kinds of Command then require two different things: -- [ ] A) A file in the project -- [ ] B) One physical mechanism on the robot -- [ ] C) A gamepad button -- [ ] D) A type of motor +- `BaseMaintainerCommand` requires the **real** subsystem. It typically runs as that subsystem's default command, continuously driving the motors toward whatever the current goal is. +- `BaseSetpointCommand` requires the **lock** (`getSetpointLock()`), not the real subsystem. -
-Answer +Why bother? If a command that just sets a new goal required the real subsystem, starting it would cancel the maintainer - the very thing doing the work of getting there. Requiring the lock instead keeps goal-setting commands mutually exclusive with each other, while leaving the maintainer running undisturbed. -**B) One physical mechanism on the robot** +The lock behaves like any other Subsystem, so it can have its own default command: -Each subsystem controls one part of the robot (drive, shooter, intake, etc.) with its own motors and sensors. +```java +shooter.getSetpointLock().setDefaultCommand(stopCommand); +``` -
+## How tos +- [Mapping Buttons to Commands](/curriculum/robot-fundamentals/operator-command-map) - hooking Commands up to gamepad buttons