Skip to content

Commit 653f64b

Browse files
authored
Merge branch 'Yet-Another-Software-Suite:master' into master
2 parents 0214cd5 + be38174 commit 653f64b

File tree

496 files changed

+27939
-11546
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

496 files changed

+27939
-11546
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,5 @@ compile_commands.json
358358
/examples/swerve_drive_maplesim/.idea
359359
/examples/swerve_drive/.idea
360360
/examples/swerve_drive/.idea
361+
362+
*.revlog

EasyCRTConfigGuide.md

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# EasyCRT Absolute Encoder Configuration Guide
2+
3+
This guide shows how to configure the EasyCRT solver (`EasyCRT` + `EasyCRTConfig`)
4+
5+
## How the solver works
6+
- You supply two absolute enocder angles (wrapping to [0,1) is taken care of by the config) plus their rotations-per-mechanism-rotation ratios.
7+
- The solver enumerates every mechanism angle that fits encoder 1 within the allowed mechanism range, predicts what encoder 2 should read, and measures modular error.
8+
- The best match inside your tolerance becomes the mechanism angle; near ties become `AMBIGUOUS`; no in-range match becomes `NO_SOLUTION`.
9+
- The iteration count stays reasonable. Typical solves are tens of iterations. Log `getLastIterations()` to view this. The gear recommender also filters gear pairs whose theoretical iterations exceed your limit.
10+
11+
## Required inputs
12+
- Provide two `Supplier<Angle>` values (encoder 1 and encoder 2). If a supplier returns `null`, it is treated as `NaN` and the solve will fail.
13+
- All other settings are configured via `EasyCRTConfig` before passing it to `EasyCRT`.
14+
15+
## Ratio / gearing setup
16+
Pick ONE path per encoder to define rotations per mechanism rotation.
17+
18+
- **Direct ratio**: `withEncoderRatios(enc1RotPerMechRot, enc2RotPerMechRot)` when you already computed the ratios. Example:
19+
```java
20+
easyCrt.withEncoderRatios(/* enc1 */ 50.0, /* enc2 */ 18.3333);
21+
```
22+
- **Shared drive gear**: `withCommonDriveGear(commonRatio, driveGearTeeth, encoder1PinionTeeth, encoder2PinionTeeth)`
23+
- `commonRatio` = mechanism rotations : shared drive gear rotations (the gear that meshes with both encoder pinions).
24+
- Seeds prime tooth counts, the common scale `k`, and stage 1 gear teeth + stage 2 ratio for gear recommendations.
25+
- Example: turret gearbox is 12:50 -> 10:110; encoders use 30T and 31T pinions driven by the 50t gear. `commonRatio` is 110.0 / 10.0 = 11.0; shared drive gear is 50T:
26+
```java
27+
easyCrt.withCommonDriveGear(/* commonRatio */ 11.0,
28+
/* driveGearTeeth */ 50,
29+
/* encoder1Pinion */ 30,
30+
/* encoder2Pinion */ 31);
31+
```
32+
- **Gear chain (simple mesh sequence)**: `withAbsoluteEncoder1Gearing(teeth...)` / `withAbsoluteEncoder2Gearing(teeth...)`
33+
- Teeth listed from mechanism-side gear to encoder pinion. Example:
34+
```java
35+
easyCrt.withAbsoluteEncoder1Gearing(50, 20, 40); // 50 drives 20, 20 drives 40
36+
easyCrt.withAbsoluteEncoder2Gearing(60, 20); // 60 drives 20
37+
```
38+
- **Explicit stages (driver, driven pairs)**: `withAbsoluteEncoder1GearingStages(driver1, driven1, driver2, driven2, ...)` / `withAbsoluteEncoder2GearingStages(...)`
39+
- Use for compound or same-shaft trains. Example:
40+
```java
41+
easyCrt.withAbsoluteEncoder1GearingStages(12, 36, 18, 60); // 12->36, then 18->60
42+
easyCrt.withAbsoluteEncoder2GearingStages(12, 60); // single stage 12->60
43+
```
44+
- **Inversion**: Configure both in one place (preferred). We reccomend that offsets be applied in the config to avoid confusion, but if your vendor's encoder supports on-device offsets, that is fine, however DO NOT set them in both places:
45+
```java
46+
easyCrt.withAbsoluteEncoderInversions(/* enc1 inverted */ false,
47+
/* enc2 inverted */ true);
48+
```
49+
Leave device-side inversion at defaults; set inversion here as the single source of truth. The CTRE CANCoder configurator in YAMS resets device inversion to a known baseline, so you will not carry stale on-device inversion.
50+
51+
Sanity checks:
52+
- Ratios must be finite and non-zero; tooth counts must be positive.
53+
- If neither direct ratios nor gearing are provided, the configuration throws an error.
54+
- When using chains or stages, verify the order (mechanism -> ... -> encoder). Reversed order yields the wrong ratio.
55+
56+
## Offsets and limits
57+
- **Offsets before wrap**: `withAbsoluteEncoderOffsets(enc1Offset, enc2Offset)` (in rotations) shifts raw readings prior to wrapping into `[0, 1)`. Set offsets here after mechanical zeroing so both encoders read as close to 0.0 rotations as possible at your reference pose. Keep device-side offsets at defaults; the CTRE CANCoder configurator resets device offsets, so the config holds the offsets. Similar to inversion, set this where you want but DO NOT do it twice.
58+
- **Motion limits**: `withMechanismRange(minAngle, maxAngle)` (rotations). The solver enumerates only within this window; narrower windows shrink the candidate set.
59+
- **Match tolerance**: `withMatchTolerance(tolerance)` (rotations of encoder 2). Start near the expected backlash mapped through encoder 2’s ratio; too small -> `NO_SOLUTION`, too large -> risk of `AMBIGUOUS`. If you always preload the turret (or mechanism) to one side of its backlash before solving, effective backlash drops and you can run a smaller tolerance. Monitor `getLastErrorRotations()` while tuning.
60+
61+
## Coverage (unique range) and primes
62+
- When you provide prime tooth counts and a common scale, `getUniqueCoverage()` returns the mechanism rotations you can uniquely represent.
63+
- Provided automatically when you use `withCommonDriveGear` (it seeds `encoder1PrimeTeeth`, `encoder2PrimeTeeth`, and `commonScaleK = commonRatio * driveGearTeeth`).
64+
- Formula: `coverageRot = lcm(encoder1PrimeTeeth, encoder2PrimeTeeth) / commonScaleK`.
65+
- `coverageSatisfiesRange()` checks whether the computed coverage is greater than or equal to your configured `maxMechanismAngle`. Use this as a guardrail when choosing pinion teeth.
66+
- Tip: pick pinion teeth that are coprime to maximize coverage; otherwise `lcm` shrinks and you may not cover your travel.
67+
68+
## Gear recommender workflow
69+
Goal: find the smallest coprime-ish gear pair that yields enough unique coverage with acceptable solve iterations.
70+
- Prereqs (often auto-set by `withCommonDriveGear`):
71+
- Stage 1 gear teeth (the shared drive gear for both encoders).
72+
- Stage 2 ratio (mechanism : drive gear).
73+
- If you do NOT use `withCommonDriveGear`, you can still seed the recommender manually with `withCrtGearRecommendationInputs(stage1GearTeeth, stage2Ratio)` before calling `withCrtGearRecommendationConstraints(...)`.
74+
- Configure constraints: `withCrtGearRecommendationConstraints(coverageMargin, minTeeth, maxTeeth, maxIterations)` and (if needed) `withCrtGearRecommendationInputs(stage1GearTeeth, stage2Ratio)`.
75+
- Runs only in simulation to avoid extra CPU on-robot.
76+
- `coverageMargin` multiplies your `maxMechanismAngle` to enforce slack (for example, 1.2 adds 20 percent headroom).
77+
- `maxIterations` rejects pairs that would require too many candidate checks per solve (the real count is visible via `getLastIterations()`).
78+
- Call `getRecommendedCrtGearPair()` in sim; it returns `Optional<CrtGearPair>` with:
79+
- `gearA`, `gearB`: tooth counts.
80+
- `coverage`: resulting unique mechanism coverage (rotations).
81+
- `lcm`, `gcd`, and `theoreticalIterations`.
82+
- Use the returned pinions as `encoder1PinionTeeth` / `encoder2PinionTeeth` in `withCommonDriveGear` (or your own chain/stage builders) and re-check `coverageSatisfiesRange()`.
83+
84+
## Practical gearing guidance
85+
- Ratio equals the total reduction to the mechanism. Ensure backlash mapped to encoder 2 does not exceed your tolerance.
86+
- Chain or belt stages: include every stage when you compute ratios or describe the chain; missing a stage collapses your coverage and can cause ambiguity.
87+
- Prime tooth choice: pick small, coprime pinions (for example, 19T + 21T) for high coverage with minimal size. Avoid sharing factors (for example, 20T + 30T) unless coverage math still clears your travel.
88+
89+
## Calibration and bring-up
90+
1) Mechanically zero the mechanism; log both absolute readings (raw rotations in [0, 1)).
91+
2) Set offsets so that the zero pose reads the desired mechanism zero after wrap (set them in the config).
92+
3) Set motion range to the actual usable travel (include soft stops if you have them).
93+
4) Compute ratios via one of the gearing helpers; confirm `coverageSatisfiesRange()` if using prime-aware inputs.
94+
5) Choose an initial `matchTolerance` based on backlash mapped to encoder 2: `backlash_mech_rot * ratio2`. If you preload to one side, you can shrink this.
95+
6) Jog through the full travel; watch `getLastStatus()` and `getLastErrorRotations()`; ensure no `AMBIGUOUS` near boundary regions.
96+
7) Power-cycle in multiple poses and confirm reconstructed angles stay consistent.
97+
98+
## Seeding a motor controller with EasyCRT
99+
Use the solved mechanism angle to initialize your motor controller's encoder so it knows its absolute position after boot:
100+
```java
101+
var easyCrtConfig = ...; // build EasyCRTConfig as shown above
102+
var easyCrtSolver = new EasyCRT(easyCrtConfig);
103+
//If the mechanism is configured using YAMS, use setEncoderPosition
104+
easyCrtSolver.getAngleOptional().ifPresent(mechAngle -> {
105+
motor.setEncoderPosition(mechAngle);
106+
});
107+
```
108+
Call this once at startup (after sensors are ready) before running closed-loop control.
109+
110+
## Troubleshooting: Common pitfalls and how to avoid them
111+
- Wrong ratio sign: mechanism turns positive but angle decreases -> set encoder inversion
112+
- Missing a gear stage: forgetting chain or belt stages yields too-small ratios; candidates overlap -> `AMBIGUOUS`.
113+
- Non-coprime pinions: shared factors shrink coverage; `coverageSatisfiesRange()` becomes false. Pick coprime counts or widen the coverage margin.
114+
- Zeroing at a wrap edge: offsets that place the parked pose near 0 or 1 can cause wrap flips from noise. If your zero offset lands within a few hundredths of 0 or 1 rotations, physically re-phase the encoder (pull the pinion or magnet, rotate a tooth or two, and remesh) so your zero sits closer to mid-window, then reset offsets in the config.
115+
- Tolerance too tight: backlash or magnet noise bigger than tolerance -> `NO_SOLUTION`. Increase tolerance or preload the mechanism to one side of backlash.
116+
- Tolerance too loose: two candidates inside tolerance -> `AMBIGUOUS`. Reduce tolerance or widen range margins so only one candidate survives.
117+
- Double inversion or offset: applying inversion or offset both on device and in config produces mirrored or shifted angles. Keep device at defaults; do inversion and offsets in the config. The CTRE CANCoder configurator resets device settings, preventing stale on-device values.
118+
- Skipping power-cycle tests: CRT must reconstruct after reboot; always validate cold-start behavior.
119+
120+
## Example configuration (encoders driven through the mechanism reduction)
121+
```java
122+
// Suppose: mechanism : drive gear = 12:1, drive gear = 50T, encoders use 19T and 23T pinions.
123+
var easyCrt =
124+
new EasyCRTConfig(enc1Supplier, enc2Supplier)
125+
.withCommonDriveGear(
126+
/* commonRatio (mech:drive) */ 12.0,
127+
/* driveGearTeeth */ 50,
128+
/* encoder1Pinion */ 19,
129+
/* encoder2Pinion */ 23)
130+
.withAbsoluteEncoderOffsets(Rotations.of(0.0), Rotations.of(0.0)) // set after mechanical zero
131+
.withMechanismRange(Rotations.of(-1.0), Rotations.of(2.0)) // -360 deg to +720 deg
132+
.withMatchTolerance(Rotations.of(0.06)) // ~1.08 deg at encoder2 for the example ratio
133+
.withAbsoluteEncoderInversions(false, false)
134+
.withCrtGearRecommendationConstraints(
135+
/* coverageMargin */ 1.2,
136+
/* minTeeth */ 15,
137+
/* maxTeeth */ 45,
138+
/* maxIterations */ 30);
139+
140+
// you can inspect:
141+
easyCrt.getUniqueCoverage(); // Optional<Angle> coverage from prime counts and common scale
142+
easyCrt.coverageSatisfiesRange(); // Does coverage exceed maxMechanismAngle?
143+
easyCrt.getRecommendedCrtGearPair(); // Suggested pair within constraints
144+
145+
// Create the solver:
146+
var easyCrtSolver = new EasyCRT(easyCrt);
147+
```
148+
149+
## More gearing examples
150+
- **Encoders using explicit stage definitions** (no CRT inputs set by gearing; seed the recommender manually):
151+
```java
152+
var easyCrt =
153+
new EasyCRTConfig(enc1, enc2)
154+
.withAbsoluteEncoder1GearingStages(14, 50, 16, 60) // compound to encoder 1
155+
.withAbsoluteEncoder2GearingStages(12, 36, 18, 54) // compound to encoder 2
156+
.withMechanismRange(Rotations.of(0.0), Rotations.of(2.0))
157+
.withAbsoluteEncoderOffsets(Rotations.of(0.01), Rotations.of(0.0)) // align to hard stop
158+
.withAbsoluteEncoderInversions(false, true)
159+
// Seed recommender since common drive inputs were not provided above
160+
.withCrtGearRecommendationInputs(
161+
/* stage1GearTeeth (shared driver) */ 48,
162+
/* stage2Ratio (mech:drive) */ 10.0)
163+
.withCrtGearRecommendationConstraints(
164+
/* coverageMargin */ 1.15,
165+
/* minTeeth */ 15,
166+
/* maxTeeth */ 55,
167+
/* maxIterations */ 30);
168+
169+
easyCrt.getRecommendedCrtGearPair();
170+
```
171+
172+
- **Encoders using chain helpers** (no CRT inputs; coverage helpers empty):
173+
```java
174+
var easyCrt =
175+
new EasyCRTConfig(enc1, enc2)
176+
.withAbsoluteEncoder1Gearing(72, 24) // 72 drives 24
177+
.withAbsoluteEncoder2Gearing(50, 20, 40) // 50 drives 20, 20 drives 40
178+
.withMechanismRange(Rotations.of(0.0), Rotations.of(1.2))
179+
.withAbsoluteEncoderInversions(false, false);
180+
```
181+
182+
## Validation checklist
183+
- Observe `getLastStatus()` while commanding moves; it should report `OK` across travel.
184+
- Ensure `getLastErrorRotations()` stays below your tolerance with margin.
185+
- Jog across theoretical wrap boundaries; verify no sudden +/-1 rotation jumps in mechanism space.
186+
- Run multiple power cycles in varied poses and confirm the resolved angle stays within your tolerance budget.

examples/Kitbot2026/.gitignore

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# This gitignore has been specially created by the WPILib team.
2+
# If you remove items from this file, intellisense might break.
3+
4+
### C++ ###
5+
# Prerequisites
6+
*.d
7+
8+
# Compiled Object files
9+
*.slo
10+
*.lo
11+
*.o
12+
*.obj
13+
14+
# Precompiled Headers
15+
*.gch
16+
*.pch
17+
18+
# Compiled Dynamic libraries
19+
*.so
20+
*.dylib
21+
*.dll
22+
23+
# Fortran module files
24+
*.mod
25+
*.smod
26+
27+
# Compiled Static libraries
28+
*.lai
29+
*.la
30+
*.a
31+
*.lib
32+
33+
# Executables
34+
*.exe
35+
*.out
36+
*.app
37+
38+
### Java ###
39+
# Compiled class file
40+
*.class
41+
42+
# Log file
43+
*.log
44+
45+
# BlueJ files
46+
*.ctxt
47+
48+
# Mobile Tools for Java (J2ME)
49+
.mtj.tmp/
50+
51+
# Package Files #
52+
*.jar
53+
*.war
54+
*.nar
55+
*.ear
56+
*.zip
57+
*.tar.gz
58+
*.rar
59+
60+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
61+
hs_err_pid*
62+
63+
### Linux ###
64+
*~
65+
66+
# temporary files which can be created if a process still has a handle open of a deleted file
67+
.fuse_hidden*
68+
69+
# KDE directory preferences
70+
.directory
71+
72+
# Linux trash folder which might appear on any partition or disk
73+
.Trash-*
74+
75+
# .nfs files are created when an open file is removed but is still being accessed
76+
.nfs*
77+
78+
### macOS ###
79+
# General
80+
.DS_Store
81+
.AppleDouble
82+
.LSOverride
83+
84+
# Icon must end with two \r
85+
Icon
86+
87+
# Thumbnails
88+
._*
89+
90+
# Files that might appear in the root of a volume
91+
.DocumentRevisions-V100
92+
.fseventsd
93+
.Spotlight-V100
94+
.TemporaryItems
95+
.Trashes
96+
.VolumeIcon.icns
97+
.com.apple.timemachine.donotpresent
98+
99+
# Directories potentially created on remote AFP share
100+
.AppleDB
101+
.AppleDesktop
102+
Network Trash Folder
103+
Temporary Items
104+
.apdisk
105+
106+
### VisualStudioCode ###
107+
.vscode/*
108+
!.vscode/settings.json
109+
!.vscode/tasks.json
110+
!.vscode/launch.json
111+
!.vscode/extensions.json
112+
113+
### Windows ###
114+
# Windows thumbnail cache files
115+
Thumbs.db
116+
ehthumbs.db
117+
ehthumbs_vista.db
118+
119+
# Dump file
120+
*.stackdump
121+
122+
# Folder config file
123+
[Dd]esktop.ini
124+
125+
# Recycle Bin used on file shares
126+
$RECYCLE.BIN/
127+
128+
# Windows Installer files
129+
*.cab
130+
*.msi
131+
*.msix
132+
*.msm
133+
*.msp
134+
135+
# Windows shortcuts
136+
*.lnk
137+
138+
### Gradle ###
139+
.gradle
140+
/build/
141+
142+
# Ignore Gradle GUI config
143+
gradle-app.setting
144+
145+
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
146+
!gradle-wrapper.jar
147+
148+
# Cache of project
149+
.gradletasknamecache
150+
151+
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
152+
# gradle/wrapper/gradle-wrapper.properties
153+
154+
# # VS Code Specific Java Settings
155+
# DO NOT REMOVE .classpath and .project
156+
.classpath
157+
.project
158+
.settings/
159+
bin/
160+
161+
# IntelliJ
162+
*.iml
163+
*.ipr
164+
*.iws
165+
.idea/
166+
out/
167+
168+
# Fleet
169+
.fleet
170+
171+
# Simulation GUI and other tools window save file
172+
networktables.json
173+
simgui.json
174+
*-window.json
175+
176+
# Simulation data log directory
177+
logs/
178+
179+
# Folder that has CTRE Phoenix Sim device config storage
180+
ctre_sim/
181+
182+
# clangd
183+
/.cache
184+
compile_commands.json
185+
186+
# Eclipse generated file for annotation processors
187+
.factorypath

0 commit comments

Comments
 (0)